From 069df08529d0d947c19055043943df679336ec8c Mon Sep 17 00:00:00 2001 From: goodboy Date: Thu, 2 Jul 2026 12:32:49 -0400 Subject: [PATCH] Type the docs-visible `examples/` scripts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Type the runtime objects (`ActorNursery`, `Portal`, `Context`, `trio.Nursery`) + fn signatures across the 16 highest-visibility, `literalinclude`-d `examples/` scripts, matching the front-page `we_are_processes.py` style — so the rendered guides show typed usage throughout, not just on the landing snippet. Spans the 3 quickstart-backing scripts + `single_func`, `remote_error_propagation`, `multiple_streams_one_portal`, `quick_cluster`, `service_discovery`, `service_daemon_discovery`, `asynchronous_generators`, `nested_actor_tree`, `concurrent_actors_primes`, `streaming_broadcast_fanout`, `rpc_bidir_streaming`, `infected_asyncio_echo_server`, `typed_payloads`. Annotation-only (no renames/logic changes); each runs green and the docs build stays warning-free. Part of the examples-typing bullet in #472. (this patch was generated in some part by [`claude-code`][claude-code-gh]) [claude-code-gh]: https://github.com/anthropics/claude-code --- examples/a_trynamic_first_scene.py | 12 +++++++----- examples/actor_spawning_and_causality.py | 7 ++++--- ...actor_spawning_and_causality_with_daemon.py | 7 ++++--- examples/asynchronous_generators.py | 7 ++++--- examples/full_fledged_streaming_service.py | 9 +++++---- examples/infected_asyncio_echo_server.py | 7 ++++--- examples/multiple_streams_one_portal.py | 18 +++++++++++++----- examples/nested_actor_tree.py | 5 ++++- .../parallelism/concurrent_actors_primes.py | 16 +++++++++++----- examples/parallelism/single_func.py | 9 +++++---- examples/quick_cluster.py | 3 ++- examples/remote_error_propagation.py | 7 ++++--- examples/rpc_bidir_streaming.py | 3 ++- examples/service_daemon_discovery.py | 4 +++- examples/service_discovery.py | 5 ++++- examples/streaming_broadcast_fanout.py | 4 +++- examples/typed_payloads.py | 3 ++- examples/uds_transport_actor_tree.py | 3 ++- 18 files changed, 83 insertions(+), 46 deletions(-) diff --git a/examples/a_trynamic_first_scene.py b/examples/a_trynamic_first_scene.py index 05d61ba9..7940437c 100644 --- a/examples/a_trynamic_first_scene.py +++ b/examples/a_trynamic_first_scene.py @@ -8,29 +8,31 @@ the_line = 'Hi my name is {}' tractor.log.get_console_log("INFO") -async def hi(): +async def hi() -> str: return the_line.format(tractor.current_actor().name) -async def say_hello(other_actor): +async def say_hello(other_actor: str) -> str: + portal: tractor.Portal async with tractor.wait_for_actor(other_actor) as portal: return await portal.run(hi) -async def main(): +async def main() -> None: """Main tractor entry point, the "master" process (for now acts as the "director"). """ + n: tractor.ActorNursery async with tractor.open_nursery() as n: print("Alright... Action!") - donny = await n.run_in_actor( + donny: tractor.Portal = await n.run_in_actor( say_hello, name='donny', # arguments are always named other_actor='gretchen', ) - gretchen = await n.run_in_actor( + gretchen: tractor.Portal = await n.run_in_actor( say_hello, name='gretchen', other_actor='donny', diff --git a/examples/actor_spawning_and_causality.py b/examples/actor_spawning_and_causality.py index 2232ae3e..221a8f07 100644 --- a/examples/actor_spawning_and_causality.py +++ b/examples/actor_spawning_and_causality.py @@ -2,17 +2,18 @@ import trio import tractor -async def cellar_door(): +async def cellar_door() -> str: assert not tractor.is_root_process() return "Dang that's beautiful" -async def main(): +async def main() -> None: """The main ``tractor`` routine. """ + n: tractor.ActorNursery async with tractor.open_nursery() as n: - portal = await n.run_in_actor( + portal: tractor.Portal = await n.run_in_actor( cellar_door, name='some_linguist', ) diff --git a/examples/actor_spawning_and_causality_with_daemon.py b/examples/actor_spawning_and_causality_with_daemon.py index b052871b..921c765d 100644 --- a/examples/actor_spawning_and_causality_with_daemon.py +++ b/examples/actor_spawning_and_causality_with_daemon.py @@ -2,19 +2,20 @@ import trio import tractor -async def movie_theatre_question(): +async def movie_theatre_question() -> str: """A question asked in a dark theatre, in a tangent (errr, I mean different) process. """ return 'have you ever seen a portal?' -async def main(): +async def main() -> None: """The main ``tractor`` routine. """ + n: tractor.ActorNursery async with tractor.open_nursery() as n: - portal = await n.start_actor( + portal: tractor.Portal = await n.start_actor( 'frank', # enable the actor to run funcs from this current module enable_modules=[__name__], diff --git a/examples/asynchronous_generators.py b/examples/asynchronous_generators.py index b037b085..b454aed8 100644 --- a/examples/asynchronous_generators.py +++ b/examples/asynchronous_generators.py @@ -13,11 +13,12 @@ async def stream_forever() -> AsyncIterator[int]: await trio.sleep(0.01) -async def main(): +async def main() -> None: + n: tractor.ActorNursery async with tractor.open_nursery() as n: - portal = await n.start_actor( + portal: tractor.Portal = await n.start_actor( 'donny', enable_modules=[__name__], ) @@ -25,7 +26,7 @@ async def main(): # this async for loop streams values from the above # async generator running in a separate process async with portal.open_stream_from(stream_forever) as stream: - count = 0 + count: int = 0 async for letter in stream: print(letter) count += 1 diff --git a/examples/full_fledged_streaming_service.py b/examples/full_fledged_streaming_service.py index 390a1b75..de4d5286 100644 --- a/examples/full_fledged_streaming_service.py +++ b/examples/full_fledged_streaming_service.py @@ -9,14 +9,14 @@ from tractor import ( # this is the first 2 actors, streamer_1 and streamer_2 -async def stream_data(seed): +async def stream_data(seed: int): for i in range(seed): yield i await trio.sleep(0.0001) # trigger scheduler # this is the third actor; the aggregator -async def aggregate(seed): +async def aggregate(seed: int): ''' Ensure that the two streams we receive match but only stream a single set of values to the parent. @@ -28,7 +28,7 @@ async def aggregate(seed): for i in range(1, 3): # fork/spawn call - portal = await an.start_actor( + portal: Portal = await an.start_actor( name=f'streamer_{i}', enable_modules=[__name__], ) @@ -37,7 +37,7 @@ async def aggregate(seed): send_chan, recv_chan = trio.open_memory_channel(500) - async def push_to_chan(portal, send_chan): + async def push_to_chan(portal: Portal, send_chan): # TODO: https://github.com/goodboy/tractor/issues/207 async with send_chan: @@ -49,6 +49,7 @@ async def aggregate(seed): print(f"FINISHED ITERATING {portal.channel.uid}") # spawn 2 trio tasks to collect streams and push to a local queue + n: trio.Nursery async with trio.open_nursery() as n: for portal in portals: diff --git a/examples/infected_asyncio_echo_server.py b/examples/infected_asyncio_echo_server.py index e8d29dc3..7332d4bc 100644 --- a/examples/infected_asyncio_echo_server.py +++ b/examples/infected_asyncio_echo_server.py @@ -28,7 +28,7 @@ async def aio_echo_server( @tractor.context async def trio_to_aio_echo_server( ctx: tractor.Context, -): +) -> None: # this will block until the ``asyncio`` task sends a "first" # message. async with tractor.to_asyncio.open_channel_from( @@ -48,10 +48,11 @@ async def trio_to_aio_echo_server( await stream.send(out) -async def main(): +async def main() -> None: + n: tractor.ActorNursery async with tractor.open_nursery() as n: - p = await n.start_actor( + p: tractor.Portal = await n.start_actor( 'aio_server', enable_modules=[__name__], infect_asyncio=True, diff --git a/examples/multiple_streams_one_portal.py b/examples/multiple_streams_one_portal.py index 3e592a45..45272b6c 100644 --- a/examples/multiple_streams_one_portal.py +++ b/examples/multiple_streams_one_portal.py @@ -5,7 +5,7 @@ import tractor log = tractor.log.get_logger('multiportal') -async def stream_data(seed=10): +async def stream_data(seed: int = 10): log.info("Starting stream task") for i in range(seed): @@ -13,7 +13,10 @@ async def stream_data(seed=10): await trio.sleep(0) # trigger scheduler -async def stream_from_portal(p, consumed): +async def stream_from_portal( + p: tractor.Portal, + consumed: list, +) -> None: async with p.open_stream_from(stream_data) as stream: async for item in stream: @@ -23,14 +26,19 @@ async def stream_from_portal(p, consumed): consumed.append(item) -async def main(): +async def main() -> None: + an: tractor.ActorNursery async with tractor.open_nursery(loglevel='info') as an: - p = await an.start_actor('stream_boi', enable_modules=[__name__]) + p: tractor.Portal = await an.start_actor( + 'stream_boi', + enable_modules=[__name__], + ) - consumed = [] + consumed: list = [] + n: trio.Nursery async with trio.open_nursery() as n: for i in range(2): n.start_soon(stream_from_portal, p, consumed) diff --git a/examples/nested_actor_tree.py b/examples/nested_actor_tree.py index a0c66b88..cb45b22c 100644 --- a/examples/nested_actor_tree.py +++ b/examples/nested_actor_tree.py @@ -41,6 +41,7 @@ async def fan_out_squares( aggregated squares to our parent. ''' + an: tractor.ActorNursery async with tractor.open_nursery() as an: portals: list[tractor.Portal] = [] for i in (1, 2): @@ -67,6 +68,7 @@ async def fan_out_squares( ) # fan out one sub-RPC per input val, concurrently. + tn: trio.Nursery async with trio.open_nursery() as tn: for i, x in enumerate(vals): tn.start_soon( @@ -83,8 +85,9 @@ async def fan_out_squares( async def main() -> None: + an: tractor.ActorNursery async with tractor.open_nursery() as an: - portal = await an.start_actor( + portal: tractor.Portal = await an.start_actor( 'supervisor', enable_modules=[__name__], ) diff --git a/examples/parallelism/concurrent_actors_primes.py b/examples/parallelism/concurrent_actors_primes.py index 748861e6..ac267aff 100644 --- a/examples/parallelism/concurrent_actors_primes.py +++ b/examples/parallelism/concurrent_actors_primes.py @@ -31,7 +31,7 @@ PRIMES = [ ] -async def is_prime(n): +async def is_prime(n: int) -> bool: if n < 2: return False if n == 2: @@ -47,7 +47,7 @@ async def is_prime(n): @acm -async def worker_pool(workers=4): +async def worker_pool(workers: int = 4): """Though it's a trivial special case for ``tractor``, the well known "worker pool" seems to be the defacto "but, I want this process pattern!" for most parallelism pilgrims. @@ -55,9 +55,10 @@ async def worker_pool(workers=4): Yes, the workers stay alive (and ready for work) until you close the context. """ + tn: tractor.ActorNursery async with tractor.open_nursery() as tn: - portals = [] + portals: list[tractor.Portal] = [] snd_chan, recv_chan = trio.open_memory_channel(len(PRIMES)) for i in range(workers): @@ -77,9 +78,14 @@ async def worker_pool(workers=4): ) -> list[bool]: # define an async (local) task to collect results from workers - async def send_result(func, value, portal): + async def send_result( + func: Callable, + value: int, + portal: tractor.Portal, + ): await snd_chan.send((value, await portal.run(func, n=value))) + n: trio.Nursery async with trio.open_nursery() as n: for value, portal in zip(sequence, itertools.cycle(portals)): @@ -101,7 +107,7 @@ async def worker_pool(workers=4): await tn.cancel() -async def main(): +async def main() -> None: async with worker_pool() as actor_map: diff --git a/examples/parallelism/single_func.py b/examples/parallelism/single_func.py index c4ea29e3..a92a7370 100644 --- a/examples/parallelism/single_func.py +++ b/examples/parallelism/single_func.py @@ -12,7 +12,7 @@ import tractor import trio -async def burn_cpu(): +async def burn_cpu() -> int: pid = os.getpid() @@ -23,17 +23,18 @@ async def burn_cpu(): return os.getpid() -async def main(): +async def main() -> None: + n: tractor.ActorNursery async with tractor.open_nursery() as n: - portal = await n.run_in_actor(burn_cpu) + portal: tractor.Portal = await n.run_in_actor(burn_cpu) # burn rubber in the parent too await burn_cpu() # wait on result from target function - pid = await portal.wait_for_result() + pid: int = await portal.wait_for_result() # end of nursery block print(f"Collected subproc {pid}") diff --git a/examples/quick_cluster.py b/examples/quick_cluster.py index 3fa4ca2a..489912c1 100644 --- a/examples/quick_cluster.py +++ b/examples/quick_cluster.py @@ -9,12 +9,13 @@ async def sleepy_jane() -> None: await trio.sleep_forever() -async def main(): +async def main() -> None: ''' Spawn a flat actor cluster, with one process per detected core. ''' portal_map: dict[str, tractor.Portal] + tn: trio.Nursery # look at this hip new syntax! async with ( diff --git a/examples/remote_error_propagation.py b/examples/remote_error_propagation.py index aa2a73b4..6ea83c6d 100644 --- a/examples/remote_error_propagation.py +++ b/examples/remote_error_propagation.py @@ -2,13 +2,14 @@ import trio import tractor -async def assert_err(): +async def assert_err() -> None: assert 0 -async def main(): +async def main() -> None: + n: tractor.ActorNursery async with tractor.open_nursery() as n: - real_actors = [] + real_actors: list[tractor.Portal] = [] for i in range(3): real_actors.append(await n.start_actor( f'actor_{i}', diff --git a/examples/rpc_bidir_streaming.py b/examples/rpc_bidir_streaming.py index c961bf20..27067e45 100644 --- a/examples/rpc_bidir_streaming.py +++ b/examples/rpc_bidir_streaming.py @@ -31,9 +31,10 @@ async def simple_rpc( async def main() -> None: + n: tractor.ActorNursery async with tractor.open_nursery() as n: - portal = await n.start_actor( + portal: tractor.Portal = await n.start_actor( 'rpc_server', enable_modules=[__name__], ) diff --git a/examples/service_daemon_discovery.py b/examples/service_daemon_discovery.py index a9086b8c..0abd4987 100644 --- a/examples/service_daemon_discovery.py +++ b/examples/service_daemon_discovery.py @@ -49,13 +49,15 @@ async def client_task() -> None: async def main() -> None: + an: tractor.ActorNursery async with tractor.open_nursery() as an: - portal = await an.start_actor( + portal: tractor.Portal = await an.start_actor( 'quote_svc', enable_modules=[__name__], ) # run the client in a separate task which discovers # the daemon purely by its registered name. + tn: trio.Nursery async with trio.open_nursery() as tn: tn.start_soon(client_task) # explicit graceful teardown of the daemon. diff --git a/examples/service_discovery.py b/examples/service_discovery.py index 574ba019..ef678951 100644 --- a/examples/service_discovery.py +++ b/examples/service_discovery.py @@ -4,14 +4,17 @@ import tractor tractor.log.get_console_log("INFO") -async def main(service_name): +async def main(service_name: str) -> None: + an: tractor.ActorNursery async with tractor.open_nursery() as an: await an.start_actor(service_name) + portal: tractor.Portal async with tractor.get_registry() as portal: print(f"Registrar is listening on {portal.channel}") + sockaddr: tractor.Portal async with tractor.wait_for_actor(service_name) as sockaddr: print(f"my_service is found at {sockaddr}") diff --git a/examples/streaming_broadcast_fanout.py b/examples/streaming_broadcast_fanout.py index 9f6900ce..15708795 100644 --- a/examples/streaming_broadcast_fanout.py +++ b/examples/streaming_broadcast_fanout.py @@ -54,8 +54,9 @@ async def consume( async def main() -> None: + an: tractor.ActorNursery async with tractor.open_nursery() as an: - portal = await an.start_actor( + portal: tractor.Portal = await an.start_actor( 'ticker', enable_modules=[__name__], ) @@ -67,6 +68,7 @@ async def main() -> None: ctx.open_stream() as stream, ): assert first == 5 + tn: trio.Nursery async with trio.open_nursery() as tn: # use `.start()` so each consumer is known # to be subscribed before the ticks flow. diff --git a/examples/typed_payloads.py b/examples/typed_payloads.py index c6352de5..58acada6 100644 --- a/examples/typed_payloads.py +++ b/examples/typed_payloads.py @@ -59,8 +59,9 @@ async def point_doubler( async def main() -> None: + an: tractor.ActorNursery async with tractor.open_nursery() as an: - portal = await an.start_actor( + portal: tractor.Portal = await an.start_actor( 'point_doubler', enable_modules=[__name__], ) diff --git a/examples/uds_transport_actor_tree.py b/examples/uds_transport_actor_tree.py index 62ee55f4..fca37df3 100644 --- a/examples/uds_transport_actor_tree.py +++ b/examples/uds_transport_actor_tree.py @@ -27,10 +27,11 @@ async def report_addr() -> str: async def main() -> None: + an: tractor.ActorNursery async with tractor.open_nursery( enable_transports=['uds'], ) as an: - portal = await an.start_actor( + portal: tractor.Portal = await an.start_actor( 'uds_child', enable_modules=[__name__], )