This is an automated email from the ASF dual-hosted git repository.

zhengruifeng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/master by this push:
     new eab92f0ad2fc [SPARK-58765][PYTHON][TEST][FOLLOWUP] Add tests for 
pa.Array.from_pandas with nested target types
eab92f0ad2fc is described below

commit eab92f0ad2fccaa92a500a9449bf2156cb260816
Author: Spenser Sun <[email protected]>
AuthorDate: Thu Aug 20 12:08:00 2026 +0800

    [SPARK-58765][PYTHON][TEST][FOLLOWUP] Add tests for pa.Array.from_pandas 
with nested target types
    
    ### What changes were proposed in this pull request?
    
    Add `PyArrowArrayFromPandasTypeNestedTests` for 
`pa.Array.from_pandas(series, type=..., safe=...)` with the nested target types 
`to_arrow_type` builds (`list<element>`, `map`, `struct`), alongside the 
existing scalar class. Four nested source rows are added to the shared 
inventory (a child-overflow list and struct, and homogeneous dicts for the map 
targets), so the default and mask goldens record their baseline.
    
    ### Why are the changes needed?
    
    The nested `from_pandas` direction was uncovered. The pinned behavior: 
`from_pandas` does not propagate `safe=` into a nested child, so an overflowing 
child value raises under both `safe=True` and `safe=False`, whereas the same 
overflow at the top level (the scalar tests) raises only under `safe=True`. The 
safe and unsafe goldens therefore match; both are kept so a future pyarrow that 
honors `safe=` in children fails loudly.
    
    ### Does this PR introduce any user-facing change?
    
    No (test-only).
    
    ### How was this patch tested?
    
    New golden tests. Swept pyarrow 18-25 x pandas 2/3: 16/16 pass, no 
overrides.
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Opus 4.8)
    
    Closes #58143 from Spenserrrr/from-pandas-type-nested-tests.
    
    Authored-by: Spenser Sun <[email protected]>
    Signed-off-by: Ruifeng Zheng <[email protected]>
---
 .../golden_pyarrow_array_from_pandas_default.csv   |  4 +
 .../golden_pyarrow_array_from_pandas_default.md    |  4 +
 .../golden_pyarrow_array_from_pandas_mask.csv      |  4 +
 .../golden_pyarrow_array_from_pandas_mask.md       |  4 +
 ..._pyarrow_array_from_pandas_type_nested_safe.csv | 11 +++
 ...n_pyarrow_array_from_pandas_type_nested_safe.md | 12 +++
 ...yarrow_array_from_pandas_type_nested_unsafe.csv | 11 +++
 ...pyarrow_array_from_pandas_type_nested_unsafe.md | 12 +++
 .../test_pyarrow_array_from_pandas_default.py      |  8 ++
 .../test_pyarrow_array_from_pandas_non_default.py  | 97 ++++++++++++++++++++++
 10 files changed, 167 insertions(+)

diff --git 
a/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_default.csv
 
b/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_default.csv
index 74a8cd3a3da2..7403a6618187 100644
--- 
a/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_default.csv
+++ 
b/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_default.csv
@@ -37,6 +37,10 @@ struct:standard      [{'a': 1, 'b': 'x'}]@Series[object]     
[[('a', 1), ('b', 'x')]]@str
 struct:nullable        [{'a': 1, 'b': 'x'}, None]@Series[object]       [[('a', 
1), ('b', 'x')], None]@struct<a: int64, b: string>
 struct<struct>:standard        [{'a': {'b': 1}}]@Series[object]        [[('a', 
{'b': 1})]]@struct<a: struct<b: int64>>
 struct<list<int64>>:standard   [{'a': [1, 2]}]@Series[object]  [[('a', [1, 
2])]]@struct<a: list<item: int64>>
+list<int64>:overflow   [[300, 2], [3]]@Series[object]  [[300, 2], 
[3]]@list<item: int64>
+struct:overflow        [{'a': 300, 'b': 'x'}]@Series[object]   [[('a', 300), 
('b', 'x')]]@struct<a: int64, b: string>
+struct<int64>:standard [{'a': 1, 'b': 2}]@Series[object]       [[('a', 1), 
('b', 2)]]@struct<a: int64, b: int64>
+struct<int64>:overflow [{'a': 300, 'b': 2}]@Series[object]     [[('a', 300), 
('b', 2)]]@struct<a: int64, b: int64>
 datetime64[ns]:standard        [Timestamp('2024-06-15 
18:30:00')]@Series[datetime64[ns]]       [2024-06-15 18:30:00]@timestamp[ns]
 datetime64[ns]:nullable        [Timestamp('2024-06-15 18:30:00'), 
NaT]@Series[datetime64[ns]]  [2024-06-15 18:30:00, None]@timestamp[ns]
 datetime64[ns]:empty   []@Series[datetime64[ns]]       []@timestamp[ns]
diff --git 
a/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_default.md
 
b/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_default.md
index 0ca6395cdb11..a9acf237c129 100644
--- 
a/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_default.md
+++ 
b/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_default.md
@@ -38,6 +38,10 @@
 | struct:nullable                 | [{'a': 1, 'b': 'x'}, None]@Series[object]  
                                          | [[('a', 1), ('b', 'x')], 
None]@struct<a: int64, b: string>      |
 | struct<struct>:standard         | [{'a': {'b': 1}}]@Series[object]           
                                          | [[('a', {'b': 1})]]@struct<a: 
struct<b: int64>>                 |
 | struct<list<int64>>:standard    | [{'a': [1, 2]}]@Series[object]             
                                          | [[('a', [1, 2])]]@struct<a: 
list<item: int64>>                  |
+| list<int64>:overflow            | [[300, 2], [3]]@Series[object]             
                                          | [[300, 2], [3]]@list<item: int64>   
                            |
+| struct:overflow                 | [{'a': 300, 'b': 'x'}]@Series[object]      
                                          | [[('a', 300), ('b', 
'x')]]@struct<a: int64, b: string>          |
+| struct<int64>:standard          | [{'a': 1, 'b': 2}]@Series[object]          
                                          | [[('a', 1), ('b', 2)]]@struct<a: 
int64, b: int64>               |
+| struct<int64>:overflow          | [{'a': 300, 'b': 2}]@Series[object]        
                                          | [[('a', 300), ('b', 2)]]@struct<a: 
int64, b: int64>             |
 | datetime64[ns]:standard         | [Timestamp('2024-06-15 
18:30:00')]@Series[datetime64[ns]]                            | [2024-06-15 
18:30:00]@timestamp[ns]                             |
 | datetime64[ns]:nullable         | [Timestamp('2024-06-15 18:30:00'), 
NaT]@Series[datetime64[ns]]                       | [2024-06-15 18:30:00, 
None]@timestamp[ns]                       |
 | datetime64[ns]:empty            | []@Series[datetime64[ns]]                  
                                          | []@timestamp[ns]                    
                            |
diff --git 
a/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_mask.csv
 
b/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_mask.csv
index 9546f28e5c72..69debccb7824 100644
--- 
a/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_mask.csv
+++ 
b/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_mask.csv
@@ -37,6 +37,10 @@ struct:standard      [{'a': 1, 'b': 'x'}]@Series[object]     
[[('a', 1), ('b', 'x')]]@str
 struct:nullable        [{'a': 1, 'b': 'x'}, None]@Series[object]       [[('a', 
1), ('b', 'x')], None]@struct<a: int64, b: string>      [[('a', 1), ('b', 
'x')], None]@struct<a: int64, b: string>
 struct<struct>:standard        [{'a': {'b': 1}}]@Series[object]        [[('a', 
{'b': 1})]]@struct<a: struct<b: int64>> [[('a', {'b': 1})]]@struct<a: struct<b: 
int64>>
 struct<list<int64>>:standard   [{'a': [1, 2]}]@Series[object]  [[('a', [1, 
2])]]@struct<a: list<item: int64>>  [[('a', [1, 2])]]@struct<a: list<item: 
int64>>
+list<int64>:overflow   [[300, 2], [3]]@Series[object]  [[300, 2], 
[3]]@list<item: int64>       [[300, 2], [3]]@list<item: int64>
+struct:overflow        [{'a': 300, 'b': 'x'}]@Series[object]   [[('a', 300), 
('b', 'x')]]@struct<a: int64, b: string>  [[('a', 300), ('b', 'x')]]@struct<a: 
int64, b: string>
+struct<int64>:standard [{'a': 1, 'b': 2}]@Series[object]       [[('a', 1), 
('b', 2)]]@struct<a: int64, b: int64>       [[('a', 1), ('b', 2)]]@struct<a: 
int64, b: int64>
+struct<int64>:overflow [{'a': 300, 'b': 2}]@Series[object]     [[('a', 300), 
('b', 2)]]@struct<a: int64, b: int64>     [[('a', 300), ('b', 2)]]@struct<a: 
int64, b: int64>
 datetime64[ns]:standard        [Timestamp('2024-06-15 
18:30:00')]@Series[datetime64[ns]]       [2024-06-15 18:30:00]@timestamp[ns]    
 [2024-06-15 18:30:00]@timestamp[ns]
 datetime64[ns]:nullable        [Timestamp('2024-06-15 18:30:00'), 
NaT]@Series[datetime64[ns]]  [2024-06-15 18:30:00, None]@timestamp[ns]       
[2024-06-15 18:30:00, None]@timestamp[ns]
 datetime64[ns]:empty   []@Series[datetime64[ns]]       []@timestamp[ns]        
[]@timestamp[ns]
diff --git 
a/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_mask.md
 
b/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_mask.md
index 1b01725a1854..b8085d64629e 100644
--- 
a/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_mask.md
+++ 
b/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_mask.md
@@ -38,6 +38,10 @@
 | struct:nullable                 | [{'a': 1, 'b': 'x'}, None]@Series[object]  
                                          | [[('a', 1), ('b', 'x')], 
None]@struct<a: int64, b: string>      | [[('a', 1), ('b', 'x')], 
None]@struct<a: int64, b: string>      |
 | struct<struct>:standard         | [{'a': {'b': 1}}]@Series[object]           
                                          | [[('a', {'b': 1})]]@struct<a: 
struct<b: int64>>                 | [[('a', {'b': 1})]]@struct<a: struct<b: 
int64>>                 |
 | struct<list<int64>>:standard    | [{'a': [1, 2]}]@Series[object]             
                                          | [[('a', [1, 2])]]@struct<a: 
list<item: int64>>                  | [[('a', [1, 2])]]@struct<a: list<item: 
int64>>                  |
+| list<int64>:overflow            | [[300, 2], [3]]@Series[object]             
                                          | [[300, 2], [3]]@list<item: int64>   
                            | [[300, 2], [3]]@list<item: int64>                 
              |
+| struct:overflow                 | [{'a': 300, 'b': 'x'}]@Series[object]      
                                          | [[('a', 300), ('b', 
'x')]]@struct<a: int64, b: string>          | [[('a', 300), ('b', 
'x')]]@struct<a: int64, b: string>          |
+| struct<int64>:standard          | [{'a': 1, 'b': 2}]@Series[object]          
                                          | [[('a', 1), ('b', 2)]]@struct<a: 
int64, b: int64>               | [[('a', 1), ('b', 2)]]@struct<a: int64, b: 
int64>               |
+| struct<int64>:overflow          | [{'a': 300, 'b': 2}]@Series[object]        
                                          | [[('a', 300), ('b', 2)]]@struct<a: 
int64, b: int64>             | [[('a', 300), ('b', 2)]]@struct<a: int64, b: 
int64>             |
 | datetime64[ns]:standard         | [Timestamp('2024-06-15 
18:30:00')]@Series[datetime64[ns]]                            | [2024-06-15 
18:30:00]@timestamp[ns]                             | [2024-06-15 
18:30:00]@timestamp[ns]                             |
 | datetime64[ns]:nullable         | [Timestamp('2024-06-15 18:30:00'), 
NaT]@Series[datetime64[ns]]                       | [2024-06-15 18:30:00, 
None]@timestamp[ns]                       | [2024-06-15 18:30:00, 
None]@timestamp[ns]                       |
 | datetime64[ns]:empty            | []@Series[datetime64[ns]]                  
                                          | []@timestamp[ns]                    
                            | []@timestamp[ns]                                  
              |
diff --git 
a/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_type_nested_safe.csv
 
b/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_type_nested_safe.csv
new file mode 100644
index 000000000000..47e9f859dc1f
--- /dev/null
+++ 
b/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_type_nested_safe.csv
@@ -0,0 +1,11 @@
+source \ target        list<element: int64>    list<element: int8>     
list<element: string>   map<string, int64>      map<string, int8>       
struct<a: int64, b: string>     struct<a: int8, b: string>
+list<int64>:standard   [[1, 2], [3]]@list<element: int64>      [[1, 2], 
[3]]@list<element: int8>       ERR@ArrowTypeError      ERR@ArrowTypeError      
ERR@ArrowTypeError      ERR@ArrowTypeError      ERR@ArrowTypeError
+list<int64>:overflow   [[300, 2], [3]]@list<element: int64>    
ERR@ArrowInvalid        ERR@ArrowTypeError      ERR@ArrowTypeError      
ERR@ArrowTypeError      ERR@ArrowTypeError      ERR@ArrowTypeError
+list<int64>:nullable   [[1, 2], None]@list<element: int64>     [[1, 2], 
None]@list<element: int8>      ERR@ArrowTypeError      ERR@ArrowTypeError      
ERR@ArrowTypeError      ERR@ArrowTypeError      ERR@ArrowTypeError
+list<int64>:null-element       [[1, None], [3]]@list<element: int64>   [[1, 
None], [3]]@list<element: int8>    ERR@ArrowTypeError      ERR@ArrowTypeError   
   ERR@ArrowTypeError      ERR@ArrowTypeError      ERR@ArrowTypeError
+list<string>:standard  ERR@ArrowInvalid        ERR@ArrowInvalid        [['a', 
'b'], ['c']]@list<element: string>       ERR@ArrowTypeError      
ERR@ArrowTypeError      ERR@ArrowTypeError      ERR@ArrowTypeError
+struct:standard        ERR@ArrowTypeError      ERR@ArrowTypeError      
ERR@ArrowTypeError      ERR@ArrowInvalid        ERR@ArrowInvalid        [[('a', 
1), ('b', 'x')]]@struct<a: int64, b: string>    [[('a', 1), ('b', 
'x')]]@struct<a: int8, b: string>
+struct:overflow        ERR@ArrowTypeError      ERR@ArrowTypeError      
ERR@ArrowTypeError      ERR@ArrowInvalid        ERR@ArrowInvalid        [[('a', 
300), ('b', 'x')]]@struct<a: int64, b: string>  ERR@ArrowInvalid
+struct:nullable        ERR@ArrowTypeError      ERR@ArrowTypeError      
ERR@ArrowTypeError      ERR@ArrowInvalid        ERR@ArrowInvalid        [[('a', 
1), ('b', 'x')], None]@struct<a: int64, b: string>      [[('a', 1), ('b', 
'x')], None]@struct<a: int8, b: string>
+struct<int64>:standard ERR@ArrowTypeError      ERR@ArrowTypeError      
ERR@ArrowTypeError      [[('a', 1), ('b', 2)]]@map<string, int64>       [[('a', 
1), ('b', 2)]]@map<string, int8>        ERR@ArrowTypeError      
ERR@ArrowTypeError
+struct<int64>:overflow ERR@ArrowTypeError      ERR@ArrowTypeError      
ERR@ArrowTypeError      [[('a', 300), ('b', 2)]]@map<string, int64>     
ERR@ArrowInvalid        ERR@ArrowTypeError      ERR@ArrowInvalid
diff --git 
a/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_type_nested_safe.md
 
b/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_type_nested_safe.md
new file mode 100644
index 000000000000..398ce8fd2c9e
--- /dev/null
+++ 
b/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_type_nested_safe.md
@@ -0,0 +1,12 @@
+| source \ target          | list<element: int64>                  | 
list<element: int8>                  | list<element: string>                    
 | map<string, int64>                          | map<string, int8>              
          | struct<a: int64, b: string>                                | 
struct<a: int8, b: string>                                |
+|--------------------------|---------------------------------------|--------------------------------------|-------------------------------------------|---------------------------------------------|------------------------------------------|------------------------------------------------------------|-----------------------------------------------------------|
+| list<int64>:standard     | [[1, 2], [3]]@list<element: int64>    | [[1, 2], 
[3]]@list<element: int8>    | ERR@ArrowTypeError                        | 
ERR@ArrowTypeError                          | ERR@ArrowTypeError                
       | ERR@ArrowTypeError                                         | 
ERR@ArrowTypeError                                        |
+| list<int64>:overflow     | [[300, 2], [3]]@list<element: int64>  | 
ERR@ArrowInvalid                     | ERR@ArrowTypeError                       
 | ERR@ArrowTypeError                          | ERR@ArrowTypeError             
          | ERR@ArrowTypeError                                         | 
ERR@ArrowTypeError                                        |
+| list<int64>:nullable     | [[1, 2], None]@list<element: int64>   | [[1, 2], 
None]@list<element: int8>   | ERR@ArrowTypeError                        | 
ERR@ArrowTypeError                          | ERR@ArrowTypeError                
       | ERR@ArrowTypeError                                         | 
ERR@ArrowTypeError                                        |
+| list<int64>:null-element | [[1, None], [3]]@list<element: int64> | [[1, 
None], [3]]@list<element: int8> | ERR@ArrowTypeError                        | 
ERR@ArrowTypeError                          | ERR@ArrowTypeError                
       | ERR@ArrowTypeError                                         | 
ERR@ArrowTypeError                                        |
+| list<string>:standard    | ERR@ArrowInvalid                      | 
ERR@ArrowInvalid                     | [['a', 'b'], ['c']]@list<element: 
string> | ERR@ArrowTypeError                          | ERR@ArrowTypeError      
                 | ERR@ArrowTypeError                                         | 
ERR@ArrowTypeError                                        |
+| struct:standard          | ERR@ArrowTypeError                    | 
ERR@ArrowTypeError                   | ERR@ArrowTypeError                       
 | ERR@ArrowInvalid                            | ERR@ArrowInvalid               
          | [[('a', 1), ('b', 'x')]]@struct<a: int64, b: string>       | 
[[('a', 1), ('b', 'x')]]@struct<a: int8, b: string>       |
+| struct:overflow          | ERR@ArrowTypeError                    | 
ERR@ArrowTypeError                   | ERR@ArrowTypeError                       
 | ERR@ArrowInvalid                            | ERR@ArrowInvalid               
          | [[('a', 300), ('b', 'x')]]@struct<a: int64, b: string>     | 
ERR@ArrowInvalid                                          |
+| struct:nullable          | ERR@ArrowTypeError                    | 
ERR@ArrowTypeError                   | ERR@ArrowTypeError                       
 | ERR@ArrowInvalid                            | ERR@ArrowInvalid               
          | [[('a', 1), ('b', 'x')], None]@struct<a: int64, b: string> | 
[[('a', 1), ('b', 'x')], None]@struct<a: int8, b: string> |
+| struct<int64>:standard   | ERR@ArrowTypeError                    | 
ERR@ArrowTypeError                   | ERR@ArrowTypeError                       
 | [[('a', 1), ('b', 2)]]@map<string, int64>   | [[('a', 1), ('b', 
2)]]@map<string, int8> | ERR@ArrowTypeError                                     
    | ERR@ArrowTypeError                                        |
+| struct<int64>:overflow   | ERR@ArrowTypeError                    | 
ERR@ArrowTypeError                   | ERR@ArrowTypeError                       
 | [[('a', 300), ('b', 2)]]@map<string, int64> | ERR@ArrowInvalid               
          | ERR@ArrowTypeError                                         | 
ERR@ArrowInvalid                                          |
\ No newline at end of file
diff --git 
a/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_type_nested_unsafe.csv
 
b/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_type_nested_unsafe.csv
new file mode 100644
index 000000000000..47e9f859dc1f
--- /dev/null
+++ 
b/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_type_nested_unsafe.csv
@@ -0,0 +1,11 @@
+source \ target        list<element: int64>    list<element: int8>     
list<element: string>   map<string, int64>      map<string, int8>       
struct<a: int64, b: string>     struct<a: int8, b: string>
+list<int64>:standard   [[1, 2], [3]]@list<element: int64>      [[1, 2], 
[3]]@list<element: int8>       ERR@ArrowTypeError      ERR@ArrowTypeError      
ERR@ArrowTypeError      ERR@ArrowTypeError      ERR@ArrowTypeError
+list<int64>:overflow   [[300, 2], [3]]@list<element: int64>    
ERR@ArrowInvalid        ERR@ArrowTypeError      ERR@ArrowTypeError      
ERR@ArrowTypeError      ERR@ArrowTypeError      ERR@ArrowTypeError
+list<int64>:nullable   [[1, 2], None]@list<element: int64>     [[1, 2], 
None]@list<element: int8>      ERR@ArrowTypeError      ERR@ArrowTypeError      
ERR@ArrowTypeError      ERR@ArrowTypeError      ERR@ArrowTypeError
+list<int64>:null-element       [[1, None], [3]]@list<element: int64>   [[1, 
None], [3]]@list<element: int8>    ERR@ArrowTypeError      ERR@ArrowTypeError   
   ERR@ArrowTypeError      ERR@ArrowTypeError      ERR@ArrowTypeError
+list<string>:standard  ERR@ArrowInvalid        ERR@ArrowInvalid        [['a', 
'b'], ['c']]@list<element: string>       ERR@ArrowTypeError      
ERR@ArrowTypeError      ERR@ArrowTypeError      ERR@ArrowTypeError
+struct:standard        ERR@ArrowTypeError      ERR@ArrowTypeError      
ERR@ArrowTypeError      ERR@ArrowInvalid        ERR@ArrowInvalid        [[('a', 
1), ('b', 'x')]]@struct<a: int64, b: string>    [[('a', 1), ('b', 
'x')]]@struct<a: int8, b: string>
+struct:overflow        ERR@ArrowTypeError      ERR@ArrowTypeError      
ERR@ArrowTypeError      ERR@ArrowInvalid        ERR@ArrowInvalid        [[('a', 
300), ('b', 'x')]]@struct<a: int64, b: string>  ERR@ArrowInvalid
+struct:nullable        ERR@ArrowTypeError      ERR@ArrowTypeError      
ERR@ArrowTypeError      ERR@ArrowInvalid        ERR@ArrowInvalid        [[('a', 
1), ('b', 'x')], None]@struct<a: int64, b: string>      [[('a', 1), ('b', 
'x')], None]@struct<a: int8, b: string>
+struct<int64>:standard ERR@ArrowTypeError      ERR@ArrowTypeError      
ERR@ArrowTypeError      [[('a', 1), ('b', 2)]]@map<string, int64>       [[('a', 
1), ('b', 2)]]@map<string, int8>        ERR@ArrowTypeError      
ERR@ArrowTypeError
+struct<int64>:overflow ERR@ArrowTypeError      ERR@ArrowTypeError      
ERR@ArrowTypeError      [[('a', 300), ('b', 2)]]@map<string, int64>     
ERR@ArrowInvalid        ERR@ArrowTypeError      ERR@ArrowInvalid
diff --git 
a/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_type_nested_unsafe.md
 
b/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_type_nested_unsafe.md
new file mode 100644
index 000000000000..398ce8fd2c9e
--- /dev/null
+++ 
b/python/pyspark/tests/upstream/pyarrow/golden_pyarrow_array_from_pandas_type_nested_unsafe.md
@@ -0,0 +1,12 @@
+| source \ target          | list<element: int64>                  | 
list<element: int8>                  | list<element: string>                    
 | map<string, int64>                          | map<string, int8>              
          | struct<a: int64, b: string>                                | 
struct<a: int8, b: string>                                |
+|--------------------------|---------------------------------------|--------------------------------------|-------------------------------------------|---------------------------------------------|------------------------------------------|------------------------------------------------------------|-----------------------------------------------------------|
+| list<int64>:standard     | [[1, 2], [3]]@list<element: int64>    | [[1, 2], 
[3]]@list<element: int8>    | ERR@ArrowTypeError                        | 
ERR@ArrowTypeError                          | ERR@ArrowTypeError                
       | ERR@ArrowTypeError                                         | 
ERR@ArrowTypeError                                        |
+| list<int64>:overflow     | [[300, 2], [3]]@list<element: int64>  | 
ERR@ArrowInvalid                     | ERR@ArrowTypeError                       
 | ERR@ArrowTypeError                          | ERR@ArrowTypeError             
          | ERR@ArrowTypeError                                         | 
ERR@ArrowTypeError                                        |
+| list<int64>:nullable     | [[1, 2], None]@list<element: int64>   | [[1, 2], 
None]@list<element: int8>   | ERR@ArrowTypeError                        | 
ERR@ArrowTypeError                          | ERR@ArrowTypeError                
       | ERR@ArrowTypeError                                         | 
ERR@ArrowTypeError                                        |
+| list<int64>:null-element | [[1, None], [3]]@list<element: int64> | [[1, 
None], [3]]@list<element: int8> | ERR@ArrowTypeError                        | 
ERR@ArrowTypeError                          | ERR@ArrowTypeError                
       | ERR@ArrowTypeError                                         | 
ERR@ArrowTypeError                                        |
+| list<string>:standard    | ERR@ArrowInvalid                      | 
ERR@ArrowInvalid                     | [['a', 'b'], ['c']]@list<element: 
string> | ERR@ArrowTypeError                          | ERR@ArrowTypeError      
                 | ERR@ArrowTypeError                                         | 
ERR@ArrowTypeError                                        |
+| struct:standard          | ERR@ArrowTypeError                    | 
ERR@ArrowTypeError                   | ERR@ArrowTypeError                       
 | ERR@ArrowInvalid                            | ERR@ArrowInvalid               
          | [[('a', 1), ('b', 'x')]]@struct<a: int64, b: string>       | 
[[('a', 1), ('b', 'x')]]@struct<a: int8, b: string>       |
+| struct:overflow          | ERR@ArrowTypeError                    | 
ERR@ArrowTypeError                   | ERR@ArrowTypeError                       
 | ERR@ArrowInvalid                            | ERR@ArrowInvalid               
          | [[('a', 300), ('b', 'x')]]@struct<a: int64, b: string>     | 
ERR@ArrowInvalid                                          |
+| struct:nullable          | ERR@ArrowTypeError                    | 
ERR@ArrowTypeError                   | ERR@ArrowTypeError                       
 | ERR@ArrowInvalid                            | ERR@ArrowInvalid               
          | [[('a', 1), ('b', 'x')], None]@struct<a: int64, b: string> | 
[[('a', 1), ('b', 'x')], None]@struct<a: int8, b: string> |
+| struct<int64>:standard   | ERR@ArrowTypeError                    | 
ERR@ArrowTypeError                   | ERR@ArrowTypeError                       
 | [[('a', 1), ('b', 2)]]@map<string, int64>   | [[('a', 1), ('b', 
2)]]@map<string, int8> | ERR@ArrowTypeError                                     
    | ERR@ArrowTypeError                                        |
+| struct<int64>:overflow   | ERR@ArrowTypeError                    | 
ERR@ArrowTypeError                   | ERR@ArrowTypeError                       
 | [[('a', 300), ('b', 2)]]@map<string, int64> | ERR@ArrowInvalid               
          | ERR@ArrowTypeError                                         | 
ERR@ArrowInvalid                                          |
\ No newline at end of file
diff --git 
a/python/pyspark/tests/upstream/pyarrow/test_pyarrow_array_from_pandas_default.py
 
b/python/pyspark/tests/upstream/pyarrow/test_pyarrow_array_from_pandas_default.py
index c3c2bb2b4f36..6b7db7ee8c18 100644
--- 
a/python/pyspark/tests/upstream/pyarrow/test_pyarrow_array_from_pandas_default.py
+++ 
b/python/pyspark/tests/upstream/pyarrow/test_pyarrow_array_from_pandas_default.py
@@ -187,6 +187,14 @@ class _PyArrowFromPandasTestBase(GoldenFileTestMixin, 
unittest.TestCase):
         sources["struct<struct>:standard"] = pd.Series([{"a": {"b": 1}}])
         sources["struct<list<int64>>:standard"] = pd.Series([{"a": [1, 2]}])
 
+        # These feed the nested type tests (non_default): a child value that 
overflows a
+        # narrower element type, and homogeneous-value dicts, which infer as 
``struct`` but
+        # convert to ``map`` when the requested type asks for one.
+        sources["list<int64>:overflow"] = pd.Series([[300, 2], [3]])
+        sources["struct:overflow"] = pd.Series([{"a": 300, "b": "x"}])
+        sources["struct<int64>:standard"] = pd.Series([{"a": 1, "b": 2}])
+        sources["struct<int64>:overflow"] = pd.Series([{"a": 300, "b": 2}])
+
         # =====================================================================
         # Temporal types
         # =====================================================================
diff --git 
a/python/pyspark/tests/upstream/pyarrow/test_pyarrow_array_from_pandas_non_default.py
 
b/python/pyspark/tests/upstream/pyarrow/test_pyarrow_array_from_pandas_non_default.py
index 67191696207c..d9a2c88fc603 100644
--- 
a/python/pyspark/tests/upstream/pyarrow/test_pyarrow_array_from_pandas_non_default.py
+++ 
b/python/pyspark/tests/upstream/pyarrow/test_pyarrow_array_from_pandas_non_default.py
@@ -279,6 +279,103 @@ class PyArrowArrayFromPandasTypeScalarTests(
         )
 
 
[email protected](
+    not have_pyarrow or not have_pandas or not have_numpy,
+    pyarrow_requirement_message or pandas_requirement_message or 
numpy_requirement_message,
+)
+class PyArrowArrayFromPandasTypeNestedTests(
+    test_pyarrow_array_from_pandas_default._PyArrowFromPandasTestBase
+):
+    """
+    Tests pa.Array.from_pandas(series, type=..., safe=...) for NESTED target 
types
+    (list / map / struct) via golden file comparison; scalar targets are 
covered by
+    PyArrowArrayFromPandasTypeScalarTests.
+
+    Targets are the container types ``to_arrow_type`` builds, spelled to match 
it
+    (``list<element: ...>``).  The behavior recorded is that from_pandas does 
NOT propagate
+    safe= into a nested child: an overflowing child value raises for both safe 
settings,
+    whereas the same overflow at the top level (the scalar tests) raises only 
under
+    safe=True.  The safe and unsafe goldens therefore match; both are kept so 
a future
+    pyarrow that honors safe= in children fails loudly.  safe=True/False are 
two methods and
+    two goldens; ``mask`` stays None.
+    """
+
+    @staticmethod
+    def _get_target_types():
+        """Nested to_arrow_type targets, each at a clean child type and a 
narrower one it can
+        overflow, so the safe= non-propagation is observable against the 
scalar goldens."""
+        return [
+            pa.list_(pa.field("element", pa.int64())),
+            pa.list_(pa.field("element", pa.int8())),
+            pa.list_(pa.field("element", pa.string())),
+            pa.map_(pa.string(), pa.int64()),
+            pa.map_(pa.string(), pa.int8()),
+            pa.struct([("a", pa.int64()), ("b", pa.string())]),
+            pa.struct([("a", pa.int8()), ("b", pa.string())]),
+        ]
+
+    def _type_source_arrays(self):
+        """
+        Nested source Series cherry-picked from the shared inventory: clean 
list/struct rows,
+        a child-overflow row per container, and homogeneous dicts for the map 
targets (a dict
+        Series infers as struct but converts to map when the type asks for 
one).
+        """
+        pool = self._numpy_backed_sources()
+        selected = [
+            "list<int64>:standard",
+            "list<int64>:overflow",
+            "list<int64>:nullable",
+            "list<int64>:null-element",
+            "list<string>:standard",
+            "struct:standard",
+            "struct:overflow",
+            "struct:nullable",
+            "struct<int64>:standard",
+            "struct<int64>:overflow",
+        ]
+        return {name: pool[name] for name in selected}
+
+    def _compare_type_matrix(self, safe, golden_file_prefix, overrides):
+        sources = self._type_source_arrays()
+        target_types = self._get_target_types()
+        target_names = [self.repr_type(t) for t in target_types]
+        target_lookup = dict(zip(target_names, target_types))
+
+        self.compare_or_generate_golden_matrix(
+            row_names=list(sources.keys()),
+            col_names=target_names,
+            compute_cell=lambda src, tgt: self._from_pandas_cell(
+                sources[src], type=target_lookup[tgt], safe=safe
+            ),
+            golden_file_prefix=golden_file_prefix,
+            overrides=overrides,
+        )
+
+    def test_from_pandas_type_nested_safe(self):
+        """Test pa.Array.from_pandas(type=<nested>, safe=True) against golden 
file."""
+        # No version-conditional cells: the nested sources are explicit 
list/dict object
+        # Series (not inference-sensitive), so the matrix holds across the 
pyarrow/pandas
+        # sweep. Entries would land here only if a future version changed a 
cell.
+        overrides: dict[tuple[str, str], str] = {}
+        self._compare_type_matrix(
+            safe=True,
+            
golden_file_prefix="golden_pyarrow_array_from_pandas_type_nested_safe",
+            overrides=overrides,
+        )
+
+    def test_from_pandas_type_nested_unsafe(self):
+        """Test pa.Array.from_pandas(type=<nested>, safe=False) against golden 
file."""
+        # Same empty overrides as the safe method, and version-stable for the 
same reason;
+        # since from_pandas does not propagate safe= into children, this 
golden also matches
+        # the safe one.
+        overrides: dict[tuple[str, str], str] = {}
+        self._compare_type_matrix(
+            safe=False,
+            
golden_file_prefix="golden_pyarrow_array_from_pandas_type_nested_unsafe",
+            overrides=overrides,
+        )
+
+
 if __name__ == "__main__":
     from pyspark.testing import main
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to