From 802774641f6dfb630b5c52264ea4307c4de92518 Mon Sep 17 00:00:00 2001
From: Tyler Goodlet <jgbt@protonmail.com>
Date: Mon, 3 Mar 2025 17:55:07 -0500
Subject: [PATCH] Fix docs tests with yet another loosie-goosie

So the KBI propagates up to the actor nursery scope and also avoid
running any `examples/multihost/` subdir scripts.
---
 examples/quick_cluster.py   | 19 +++++++++++--------
 tests/test_docs_examples.py | 37 +++++++++++++++++++++++--------------
 2 files changed, 34 insertions(+), 22 deletions(-)

diff --git a/examples/quick_cluster.py b/examples/quick_cluster.py
index ca692a90..2378a3cf 100644
--- a/examples/quick_cluster.py
+++ b/examples/quick_cluster.py
@@ -3,20 +3,18 @@ import trio
 import tractor
 
 
-async def sleepy_jane():
-    uid = tractor.current_actor().uid
+async def sleepy_jane() -> None:
+    uid: tuple = tractor.current_actor().uid
     print(f'Yo i am actor {uid}')
     await trio.sleep_forever()
 
 
 async def main():
     '''
-    Spawn a flat actor cluster, with one process per
-    detected core.
+    Spawn a flat actor cluster, with one process per detected core.
 
     '''
     portal_map: dict[str, tractor.Portal]
-    results: dict[str, str]
 
     # look at this hip new syntax!
     async with (
@@ -25,11 +23,16 @@ async def main():
             modules=[__name__]
         ) as portal_map,
 
-        trio.open_nursery() as n,
+        trio.open_nursery(
+            strict_exception_groups=False,
+        ) as tn,
     ):
 
         for (name, portal) in portal_map.items():
-            n.start_soon(portal.run, sleepy_jane)
+            tn.start_soon(
+                portal.run,
+                sleepy_jane,
+            )
 
         await trio.sleep(0.5)
 
@@ -41,4 +44,4 @@ if __name__ == '__main__':
     try:
         trio.run(main)
     except KeyboardInterrupt:
-        pass
+        print('trio cancelled by KBI')
diff --git a/tests/test_docs_examples.py b/tests/test_docs_examples.py
index fdf54bca..cc4904f8 100644
--- a/tests/test_docs_examples.py
+++ b/tests/test_docs_examples.py
@@ -19,7 +19,7 @@ from tractor._testing import (
 @pytest.fixture
 def run_example_in_subproc(
     loglevel: str,
-    testdir: pytest.Testdir,
+    testdir: pytest.Pytester,
     reg_addr: tuple[str, int],
 ):
 
@@ -81,28 +81,36 @@ def run_example_in_subproc(
 
     # walk yields: (dirpath, dirnames, filenames)
     [
-        (p[0], f) for p in os.walk(examples_dir()) for f in p[2]
+        (p[0], f)
+        for p in os.walk(examples_dir())
+        for f in p[2]
 
-        if '__' not in f
-        and f[0] != '_'
-        and 'debugging' not in p[0]
-        and 'integration' not in p[0]
-        and 'advanced_faults' not in p[0]
-        and 'multihost' not in p[0]
+        if (
+            '__' not in f
+            and f[0] != '_'
+            and 'debugging' not in p[0]
+            and 'integration' not in p[0]
+            and 'advanced_faults' not in p[0]
+            and 'multihost' not in p[0]
+        )
     ],
-
     ids=lambda t: t[1],
 )
-def test_example(run_example_in_subproc, example_script):
-    """Load and run scripts from this repo's ``examples/`` dir as a user
+def test_example(
+    run_example_in_subproc,
+    example_script,
+):
+    '''
+    Load and run scripts from this repo's ``examples/`` dir as a user
     would copy and pasing them into their editor.
 
     On windows a little more "finessing" is done to make
     ``multiprocessing`` play nice: we copy the ``__main__.py`` into the
     test directory and invoke the script as a module with ``python -m
     test_example``.
-    """
-    ex_file = os.path.join(*example_script)
+
+    '''
+    ex_file: str = os.path.join(*example_script)
 
     if 'rpc_bidir_streaming' in ex_file and sys.version_info < (3, 9):
         pytest.skip("2-way streaming example requires py3.9 async with syntax")
@@ -128,7 +136,8 @@ def test_example(run_example_in_subproc, example_script):
                     # shouldn't eventually once we figure out what's
                     # a better way to be explicit about aio side
                     # cancels?
-                    and 'asyncio.exceptions.CancelledError' not in last_error
+                    and
+                    'asyncio.exceptions.CancelledError' not in last_error
                 ):
                     raise Exception(errmsg)