Skip to content

Conversation

@reiase
Copy link
Contributor

@reiase reiase commented Jan 10, 2026

Overview:

Details:

Where should the reviewer start?

Related Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to)

  • closes GitHub issue: #xxx

…orator

- Replaced all instances of the @as_actor decorator with @Remote in documentation files, including API references, guides, and examples.
- Updated code snippets to demonstrate the new usage patterns with the @Remote decorator, ensuring consistency across all documentation.
- Enhanced examples to include initialization and shutdown processes, aligning with the new actor creation workflow.
- Adjusted translations in Chinese documentation to match the updated terminology and examples.
…nt loops

- Enhanced the `ray` compatibility module to allow `ray.init()` to function correctly when called from within an existing event loop, such as in Jupyter or pytest-asyncio environments.
- Introduced a background thread to manage a dedicated event loop, ensuring compatibility with asynchronous operations.
- Added a new test to validate the behavior of the `ray` module under these conditions, confirming that actor creation and interaction work as expected.
- Refactored existing methods to utilize the new event loop management, improving overall robustness and usability.
- Cleaned up whitespace in the `README.md`, `remote_actor_example.py`, and `ray.py` files to enhance code clarity.
- Adjusted list comprehensions and threading initialization for better formatting and alignment.
- Added a blank line in the test file `test_new_api.py` to improve separation of code sections.
- Removed unnecessary blank lines in `test_ray_compat_running_loop.py` to streamline the code structure.
_system = None
_loop = None
_thread = None
_loop_ready = None

Check notice

Code scanning / CodeQL

Unused global variable Note

The global variable '_loop_ready' is not used.

Copilot Autofix

AI 5 days ago

In general, an unused global variable should either be removed or renamed to make its intentionally-unused nature clear. Here, _loop_ready is not used for any behavior; it merely mirrors the local variable ready inside _start_background_loop. Removing it does not change the synchronization logic, because the code already waits on ready directly.

The best fix without changing functionality is:

  • Remove _loop_ready from the module-level “Global state” declarations.
  • Remove _loop_ready from the global statement in _start_background_loop.
  • Remove the assignment _loop_ready = ready.

All changes occur in python/pulsing/compat/ray.py in the snippet around lines 47–52 and 67–73. No new imports or helper methods are needed.

Suggested changeset 1
python/pulsing/compat/ray.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/python/pulsing/compat/ray.py b/python/pulsing/compat/ray.py
--- a/python/pulsing/compat/ray.py
+++ b/python/pulsing/compat/ray.py
@@ -48,7 +48,6 @@
 _system = None
 _loop = None
 _thread = None
-_loop_ready = None
 
 
 def _ensure_not_initialized(ignore_reinit_error: bool) -> None:
@@ -64,12 +63,11 @@
 
     This is required when the caller is already inside a running event loop.
     """
-    global _thread, _loop, _loop_ready
+    global _thread, _loop
     if _thread is not None:
         return
 
     ready = threading.Event()
-    _loop_ready = ready
 
     def _thread_main():
         global _loop
EOF
@@ -48,7 +48,6 @@
_system = None
_loop = None
_thread = None
_loop_ready = None


def _ensure_not_initialized(ignore_reinit_error: bool) -> None:
@@ -64,12 +63,11 @@

This is required when the caller is already inside a running event loop.
"""
global _thread, _loop, _loop_ready
global _thread, _loop
if _thread is not None:
return

ready = threading.Event()
_loop_ready = ready

def _thread_main():
global _loop
Copilot is powered by AI and may make mistakes. Always verify output.
return

ready = threading.Event()
_loop_ready = ready

Check notice

Code scanning / CodeQL

Unused global variable Note

The global variable '_loop_ready' is not used.

Copilot Autofix

AI 5 days ago

To fix the problem, we should remove the unused global variable rather than keep writing to it. That means deleting both the module-level declaration _loop_ready = None and the assignment _loop_ready = ready inside _start_background_loop. The rest of the code already uses the local ready to block until the loop is initialized (ready.wait()), so removing _loop_ready does not change behavior.

Concretely, in python/pulsing/compat/ray.py:

  • Remove the line defining _loop_ready = None in the “Global state” block.
  • In _start_background_loop, remove _loop_ready from the global statement and delete the line _loop_ready = ready.
  • No imports, methods, or other definitions are needed to support this change, since _loop_ready was never read.
Suggested changeset 1
python/pulsing/compat/ray.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/python/pulsing/compat/ray.py b/python/pulsing/compat/ray.py
--- a/python/pulsing/compat/ray.py
+++ b/python/pulsing/compat/ray.py
@@ -48,7 +48,6 @@
 _system = None
 _loop = None
 _thread = None
-_loop_ready = None
 
 
 def _ensure_not_initialized(ignore_reinit_error: bool) -> None:
@@ -64,12 +63,11 @@
 
     This is required when the caller is already inside a running event loop.
     """
-    global _thread, _loop, _loop_ready
+    global _thread, _loop
     if _thread is not None:
         return
 
     ready = threading.Event()
-    _loop_ready = ready
 
     def _thread_main():
         global _loop
EOF
@@ -48,7 +48,6 @@
_system = None
_loop = None
_thread = None
_loop_ready = None


def _ensure_not_initialized(ignore_reinit_error: bool) -> None:
@@ -64,12 +63,11 @@

This is required when the caller is already inside a running event loop.
"""
global _thread, _loop, _loop_ready
global _thread, _loop
if _thread is not None:
return

ready = threading.Event()
_loop_ready = ready

def _thread_main():
global _loop
Copilot is powered by AI and may make mistakes. Always verify output.
if _system is not None:
try:
_run_coro_sync(_system.shutdown())
except Exception:

Check notice

Code scanning / CodeQL

Empty except Note

'except' clause does nothing but pass and there is no explanatory comment.

Copilot Autofix

AI 5 days ago

In general, the fix is to avoid empty except blocks: either narrow the caught exceptions and handle them explicitly, or at least log them with enough context. For a shutdown routine that is intended not to raise, the safest minimal-change approach is to keep catching Exception but log the error rather than pass.

Concretely for python/pulsing/compat/ray.py:

  • Add an import for the standard logging module near the existing imports.
  • Replace each except Exception: pass in shutdown() with except Exception as exc: followed by a logging.getLogger(__name__).warning(...) (or error) call that records what failed and includes exc_info=True so the traceback is logged.
  • Do not change the function’s external behavior: shutdown() should still not propagate these exceptions and should still reset _system, _thread, _loop_ready, and _loop as it currently does.

All changes are confined to this file and require only the standard library logging module; no new external dependencies are needed.

Suggested changeset 1
python/pulsing/compat/ray.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/python/pulsing/compat/ray.py b/python/pulsing/compat/ray.py
--- a/python/pulsing/compat/ray.py
+++ b/python/pulsing/compat/ray.py
@@ -40,6 +40,7 @@
 import concurrent.futures
 import inspect
 import threading
+import logging
 from typing import Any, TypeVar
 
 T = TypeVar("T")
@@ -260,18 +261,28 @@
     if _system is not None:
         try:
             _run_coro_sync(_system.shutdown())
-        except Exception:
-            pass
+        except Exception as exc:
+            logging.getLogger(__name__).warning(
+                "Error during Pulsing system shutdown: %s", exc, exc_info=True
+            )
         _system = None
         if _thread is not None and _loop is not None:
             try:
                 _loop.call_soon_threadsafe(_loop.stop)
-            except Exception:
-                pass
+            except Exception as exc:
+                logging.getLogger(__name__).warning(
+                    "Error while stopping Pulsing background event loop: %s",
+                    exc,
+                    exc_info=True,
+                )
             try:
                 _thread.join(timeout=2.0)
-            except Exception:
-                pass
+            except Exception as exc:
+                logging.getLogger(__name__).warning(
+                    "Error while joining Pulsing background thread: %s",
+                    exc,
+                    exc_info=True,
+                )
             _thread = None
             _loop_ready = None
             _loop = None
EOF
@@ -40,6 +40,7 @@
import concurrent.futures
import inspect
import threading
import logging
from typing import Any, TypeVar

T = TypeVar("T")
@@ -260,18 +261,28 @@
if _system is not None:
try:
_run_coro_sync(_system.shutdown())
except Exception:
pass
except Exception as exc:
logging.getLogger(__name__).warning(
"Error during Pulsing system shutdown: %s", exc, exc_info=True
)
_system = None
if _thread is not None and _loop is not None:
try:
_loop.call_soon_threadsafe(_loop.stop)
except Exception:
pass
except Exception as exc:
logging.getLogger(__name__).warning(
"Error while stopping Pulsing background event loop: %s",
exc,
exc_info=True,
)
try:
_thread.join(timeout=2.0)
except Exception:
pass
except Exception as exc:
logging.getLogger(__name__).warning(
"Error while joining Pulsing background thread: %s",
exc,
exc_info=True,
)
_thread = None
_loop_ready = None
_loop = None
Copilot is powered by AI and may make mistakes. Always verify output.
if _thread is not None and _loop is not None:
try:
_loop.call_soon_threadsafe(_loop.stop)
except Exception:

Check notice

Code scanning / CodeQL

Empty except Note

'except' clause does nothing but pass and there is no explanatory comment.

Copilot Autofix

AI 5 days ago

In general, empty except blocks should be replaced with logic that either (a) handles specific, expected exceptions or (b) logs unexpected exceptions while optionally re-raising or suppressing them with a clear rationale. For shutdown/cleanup paths where we want to be robust and not raise, logging and then suppressing is usually appropriate.

For this file, the best fix that preserves behavior (shutdown remains non-throwing) is to keep catching Exception but log the exception instead of silently passing. Since we cannot assume any project-specific logging utilities, we can safely use the standard-library logging module. We will:

  1. Add an import for logging near the top of python/pulsing/compat/ray.py.
  2. In shutdown(), replace each except Exception: pass with except Exception as exc: and call logging.getLogger(__name__).exception("...") with a message indicating which shutdown step failed. logger.exception includes the stack trace, preserving debugging information while maintaining the current non-raising behavior.

Specific changes:

  • At the imports region (around line 39–43), add import logging.
  • Around line 261–264, replace:
    try:
        _run_coro_sync(_system.shutdown())
    except Exception:
        pass
    with a version that logs the exception.
  • Around line 267–270, replace:
    try:
        _loop.call_soon_threadsafe(_loop.stop)
    except Exception:
        pass
    with a version that logs the exception.
  • Around line 271–274, replace:
    try:
        _thread.join(timeout=2.0)
    except Exception:
        pass
    with a version that logs the exception.

This keeps external behavior (no exceptions propagated from shutdown()) while ensuring exceptions are no longer silently ignored.


Suggested changeset 1
python/pulsing/compat/ray.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/python/pulsing/compat/ray.py b/python/pulsing/compat/ray.py
--- a/python/pulsing/compat/ray.py
+++ b/python/pulsing/compat/ray.py
@@ -40,6 +40,7 @@
 import concurrent.futures
 import inspect
 import threading
+import logging
 from typing import Any, TypeVar
 
 T = TypeVar("T")
@@ -260,18 +261,24 @@
     if _system is not None:
         try:
             _run_coro_sync(_system.shutdown())
-        except Exception:
-            pass
+        except Exception as exc:
+            logging.getLogger(__name__).exception(
+                "Error while shutting down Pulsing actor system", exc_info=exc
+            )
         _system = None
         if _thread is not None and _loop is not None:
             try:
                 _loop.call_soon_threadsafe(_loop.stop)
-            except Exception:
-                pass
+            except Exception as exc:
+                logging.getLogger(__name__).exception(
+                    "Error while stopping background event loop", exc_info=exc
+                )
             try:
                 _thread.join(timeout=2.0)
-            except Exception:
-                pass
+            except Exception as exc:
+                logging.getLogger(__name__).exception(
+                    "Error while joining background thread", exc_info=exc
+                )
             _thread = None
             _loop_ready = None
             _loop = None
EOF
@@ -40,6 +40,7 @@
import concurrent.futures
import inspect
import threading
import logging
from typing import Any, TypeVar

T = TypeVar("T")
@@ -260,18 +261,24 @@
if _system is not None:
try:
_run_coro_sync(_system.shutdown())
except Exception:
pass
except Exception as exc:
logging.getLogger(__name__).exception(
"Error while shutting down Pulsing actor system", exc_info=exc
)
_system = None
if _thread is not None and _loop is not None:
try:
_loop.call_soon_threadsafe(_loop.stop)
except Exception:
pass
except Exception as exc:
logging.getLogger(__name__).exception(
"Error while stopping background event loop", exc_info=exc
)
try:
_thread.join(timeout=2.0)
except Exception:
pass
except Exception as exc:
logging.getLogger(__name__).exception(
"Error while joining background thread", exc_info=exc
)
_thread = None
_loop_ready = None
_loop = None
Copilot is powered by AI and may make mistakes. Always verify output.
pass
try:
_thread.join(timeout=2.0)
except Exception:

Check notice

Code scanning / CodeQL

Empty except Note

'except' clause does nothing but pass and there is no explanatory comment.

Copilot Autofix

AI 5 days ago

In general, the fix is to avoid empty except blocks: either narrow the exception type and handle it explicitly, or at least record what went wrong (e.g., via logging) while still preventing the exception from propagating if that’s desired.

For this specific shutdown function, the best low-impact fix is to add simple logging in each except Exception clause. That way, shutdown remains non-throwing (so existing callers’ behavior doesn’t change), but any failures in _system.shutdown(), stopping the loop, or joining the thread are visible during debugging. We can use Python’s standard logging module, which is a well-known library and doesn’t add external dependencies. Concretely:

  • Add import logging near the top of python/pulsing/compat/ray.py alongside the other imports.
  • Replace each except Exception: pass in shutdown with an except Exception as exc: block that calls logging.getLogger(__name__).exception("...") with a message indicating which shutdown step failed. Using .exception logs the full traceback, which is valuable for debugging.

No new helper methods or non-standard imports are needed; just the standard library logging and the updated except blocks, all within the shown file.

Suggested changeset 1
python/pulsing/compat/ray.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/python/pulsing/compat/ray.py b/python/pulsing/compat/ray.py
--- a/python/pulsing/compat/ray.py
+++ b/python/pulsing/compat/ray.py
@@ -41,6 +41,7 @@
 import inspect
 import threading
 from typing import Any, TypeVar
+import logging
 
 T = TypeVar("T")
 
@@ -260,18 +261,24 @@
     if _system is not None:
         try:
             _run_coro_sync(_system.shutdown())
-        except Exception:
-            pass
+        except Exception as exc:
+            logging.getLogger(__name__).exception(
+                "Error while shutting down Pulsing system", exc_info=exc
+            )
         _system = None
         if _thread is not None and _loop is not None:
             try:
                 _loop.call_soon_threadsafe(_loop.stop)
-            except Exception:
-                pass
+            except Exception as exc:
+                logging.getLogger(__name__).exception(
+                    "Error while stopping background event loop", exc_info=exc
+                )
             try:
                 _thread.join(timeout=2.0)
-            except Exception:
-                pass
+            except Exception as exc:
+                logging.getLogger(__name__).exception(
+                    "Error while joining background thread", exc_info=exc
+                )
             _thread = None
             _loop_ready = None
             _loop = None
EOF
@@ -41,6 +41,7 @@
import inspect
import threading
from typing import Any, TypeVar
import logging

T = TypeVar("T")

@@ -260,18 +261,24 @@
if _system is not None:
try:
_run_coro_sync(_system.shutdown())
except Exception:
pass
except Exception as exc:
logging.getLogger(__name__).exception(
"Error while shutting down Pulsing system", exc_info=exc
)
_system = None
if _thread is not None and _loop is not None:
try:
_loop.call_soon_threadsafe(_loop.stop)
except Exception:
pass
except Exception as exc:
logging.getLogger(__name__).exception(
"Error while stopping background event loop", exc_info=exc
)
try:
_thread.join(timeout=2.0)
except Exception:
pass
except Exception as exc:
logging.getLogger(__name__).exception(
"Error while joining background thread", exc_info=exc
)
_thread = None
_loop_ready = None
_loop = None
Copilot is powered by AI and may make mistakes. Always verify output.
except Exception:
pass
_thread = None
_loop_ready = None

Check notice

Code scanning / CodeQL

Unused global variable Note

The global variable '_loop_ready' is not used.

Copilot Autofix

AI 5 days ago

In general, to fix an unused global variable that is not intentionally unused, remove the variable: delete its definition, remove it from any global declarations, and remove any assignments to it. This eliminates dead state and the associated CodeQL warning without affecting program behavior, as long as the variable truly is never read.

For this specific case in python/pulsing/compat/ray.py, the best fix is:

  • Remove the module-level declaration _loop_ready = None (line 51).
  • Remove _loop_ready from the global statement in shutdown (line 258), leaving only the actually used globals.
  • Remove the assignment _loop_ready = None in shutdown (line 276).

No new imports or methods are needed. These changes are fully localized to the shown file and only touch _loop_ready, which, per the snippet, has no reads, so they do not change existing functionality.

Suggested changeset 1
python/pulsing/compat/ray.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/python/pulsing/compat/ray.py b/python/pulsing/compat/ray.py
--- a/python/pulsing/compat/ray.py
+++ b/python/pulsing/compat/ray.py
@@ -48,7 +48,6 @@
 _system = None
 _loop = None
 _thread = None
-_loop_ready = None
 
 
 def _ensure_not_initialized(ignore_reinit_error: bool) -> None:
@@ -255,7 +254,7 @@
 
 def shutdown() -> None:
     """Shutdown Pulsing (Ray-compatible)"""
-    global _system, _loop, _thread, _loop_ready
+    global _system, _loop, _thread
 
     if _system is not None:
         try:
@@ -273,7 +272,6 @@
             except Exception:
                 pass
             _thread = None
-            _loop_ready = None
             _loop = None
         else:
             _loop = None
EOF
@@ -48,7 +48,6 @@
_system = None
_loop = None
_thread = None
_loop_ready = None


def _ensure_not_initialized(ignore_reinit_error: bool) -> None:
@@ -255,7 +254,7 @@

def shutdown() -> None:
"""Shutdown Pulsing (Ray-compatible)"""
global _system, _loop, _thread, _loop_ready
global _system, _loop, _thread

if _system is not None:
try:
@@ -273,7 +272,6 @@
except Exception:
pass
_thread = None
_loop_ready = None
_loop = None
else:
_loop = None
Copilot is powered by AI and may make mistakes. Always verify output.
@codecov-commenter
Copy link

Codecov Report

❌ Patch coverage is 83.68421% with 31 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
python/pulsing/compat/ray.py 86.16% 22 Missing ⚠️
python/pulsing/actor/__init__.py 65.21% 8 Missing ⚠️
python/pulsing/actor/remote.py 83.33% 1 Missing ⚠️
Files with missing lines Coverage Δ
python/pulsing/__init__.py 100.00% <ø> (ø)
python/pulsing/compat/__init__.py 100.00% <100.00%> (ø)
python/pulsing/actor/remote.py 54.88% <83.33%> (+0.85%) ⬆️
python/pulsing/actor/__init__.py 76.47% <65.21%> (-9.25%) ⬇️
python/pulsing/compat/ray.py 86.16% <86.16%> (ø)

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@reiase reiase merged commit 1118471 into main Jan 11, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants