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

gurwls223 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 38d3af27535d [SPARK-54954][PYTHON] Fix remote related type hints in 
util.py
38d3af27535d is described below

commit 38d3af27535de2604e137a4d71246210030eaeab
Author: Tian Gao <[email protected]>
AuthorDate: Fri Jan 9 07:01:42 2026 +0900

    [SPARK-54954][PYTHON] Fix remote related type hints in util.py
    
    ### What changes were proposed in this pull request?
    
    * Add overload stubs for `remote_only`.
    * Distinguish remote and normal SparkSession
    * Do some type assertions so we don't need all the ignore comments
    
    ### Why are the changes needed?
    
    When we do something like
    ```python
    property
    remote_only
    def method(self):
        ...
    ```
    
    The latest version of mypy is not happy because it believes `remote_only` 
can return a `property`. We can't do `property` on a `property`.
    
    By adding the explicit overload, mypy knows that `remote_only` always 
return a callable when given a callable.
    
    ### Does this PR introduce _any_ user-facing change?
    
    No
    
    ### How was this patch tested?
    
    Wait for CI.
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Generated-by: Cursor (claude-4.5-opus-high)
    
    Closes #53722 from gaogaotiantian/fix-remote-only-overload.
    
    Authored-by: Tian Gao <[email protected]>
    Signed-off-by: Hyukjin Kwon <[email protected]>
---
 python/pyspark/sql/utils.py | 13 ++++++++++++-
 python/pyspark/util.py      | 24 ++++++++++++++----------
 2 files changed, 26 insertions(+), 11 deletions(-)

diff --git a/python/pyspark/sql/utils.py b/python/pyspark/sql/utils.py
index b0782d04cba3..d61a6ff642a4 100644
--- a/python/pyspark/sql/utils.py
+++ b/python/pyspark/sql/utils.py
@@ -24,6 +24,7 @@ from typing import (
     Dict,
     Optional,
     List,
+    overload,
     Sequence,
     TYPE_CHECKING,
     cast,
@@ -488,7 +489,17 @@ class NumpyHelper:
         return [start + step * i for i in range(num)]
 
 
-def remote_only(func: Union[Callable, property]) -> Union[Callable, property]:
+@overload
+def remote_only(func: property) -> property:
+    ...
+
+
+@overload
+def remote_only(func: FuncT) -> FuncT:
+    ...
+
+
+def remote_only(func: Union[FuncT, property]) -> Union[FuncT, property]:
     """
     Decorator to mark a function or method as only available in Spark Connect.
 
diff --git a/python/pyspark/util.py b/python/pyspark/util.py
index a9c36fb2ae6b..9f5fad57cb14 100644
--- a/python/pyspark/util.py
+++ b/python/pyspark/util.py
@@ -393,11 +393,15 @@ def inheritable_thread_target(f: Optional[Union[Callable, 
"SparkSession"]] = Non
 
     # Spark Connect
     if is_remote():
+        from pyspark.sql.connect.session import SparkSession as 
RemoteSparkSession
+
         session = f
-        assert session is not None, "Spark Connect session must be provided."
 
         def outer(ff: Callable) -> Callable:
-            thread_local = session.client.thread_local  # type: 
ignore[union-attr, operator]
+            assert isinstance(
+                session, RemoteSparkSession
+            ), "f is expected to be SparkSession for spark connect"
+            thread_local = session.client.thread_local
             session_client_thread_local_attrs = [
                 (attr, copy.deepcopy(value))
                 for (
@@ -409,15 +413,15 @@ def inheritable_thread_target(f: Optional[Union[Callable, 
"SparkSession"]] = Non
             @functools.wraps(ff)
             def inner(*args: Any, **kwargs: Any) -> Any:
                 # Propagates the active remote spark session to the current 
thread.
-                from pyspark.sql.connect.session import SparkSession as 
RemoteSparkSession
+                assert isinstance(
+                    session, RemoteSparkSession
+                ), "f is expected to be SparkSession for spark connect"
 
-                RemoteSparkSession._set_default_and_active_session(
-                    session  # type: ignore[arg-type]
-                )
+                RemoteSparkSession._set_default_and_active_session(session)
                 # Set thread locals in child thread.
                 for attr, value in session_client_thread_local_attrs:
                     setattr(
-                        session.client.thread_local,  # type: 
ignore[union-attr, operator]
+                        session.client.thread_local,
                         attr,
                         value,
                     )
@@ -437,7 +441,6 @@ def inheritable_thread_target(f: Optional[Union[Callable, 
"SparkSession"]] = Non
 
         if isinstance(f, SparkSession):
             session = f
-            assert session is not None
             tags = set(session.getTags())
             # Local properties are copied when wrapping the function.
             assert SparkContext._active_spark_context is not None
@@ -561,7 +564,8 @@ class InheritableThread(threading.Thread):
             def copy_local_properties(*a: Any, **k: Any) -> Any:
                 # Set tags in child thread.
                 assert hasattr(self, "_tags")
-                thread_local = session.client.thread_local  # type: 
ignore[union-attr, operator]
+                assert session is not None
+                thread_local = session.client.thread_local
                 thread_local.tags = self._tags  # type: ignore[has-type]
                 return target(*a, **k)
 
@@ -596,7 +600,7 @@ class InheritableThread(threading.Thread):
         if is_remote():
             # Spark Connect
             assert hasattr(self, "_session")
-            thread_local = self._session.client.thread_local  # type: 
ignore[union-attr, operator]
+            thread_local = self._session.client.thread_local
             if not hasattr(thread_local, "tags"):
                 thread_local.tags = set()
             self._tags = set(thread_local.tags)


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

Reply via email to