Repository navigation
Make DrivineAssembly pi-pilgrim 0.4's AsyncPilgrimAssembly, so await close() closes the pools again - #236
Merged
Conversation
…ses the pools again 0.3.0 moved DrivineAssembly onto pi-pilgrim's lifecycle and dropped its async close(), so 0.2.0's documented shutdown, await assembly.drivine.close(), reached pi-pilgrim's sync close(), which refuses once the registry is made, and left the drivers and pools open. close() is back on the async assembly. It closes the assembly at once when nothing needs awaiting, and otherwise returns aclose() to await, so an application assembly's sync close(), which calls it without awaiting, still closes it. with DrivineAssembly() now refuses and points to async with. scripts/unasync.py leaves these out of the sync assembly, whose close() is pi-pilgrim's. The README says what changed from 0.2.0. Fixes #228
…n what close() returns, keep the refusal text out of the sync copy, and say when close() must be awaited
# Conflicts: # README.md
…close() closes it and so does a holder's sync close pi-pilgrim 0.4.0 has an AsyncPilgrimAssembly whose close() is aclose(), and closes a held or owned assembly through its own lifecycle. On it, DrivineAssembly drops its sync close() override, the finished coroutine it returned, and the match on pi-pilgrim's refusal text. An assembly holding Drivine as a component, self.shared(DrivineAssembly), now closes it with a sync close() while it has no registry, where it raised an ExceptionGroup. A refusal is now AsyncTeardownRequired. __enter__ stays, to name the sync API in its refusal, so unasync's ASYNC_ONLY keeps only it; the sync DrivineAssembly is unchanged.
…rom the start, check the sync assembly is a plain one, and keep uv.lock's revision
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #228
What was wrong
0.2.0's README said to shut down with
await assembly.drivine.close(). #195 movedDrivineAssemblyonto pi-pilgrim's lifecycle and removed its asyncclose(). So in 0.3.0 that call reaches pi-pilgrim's syncclose(). Once the registry is made, that raisesPilgrimError ... Close it with await aclose()and leaves the drivers and pools open.The fix
pi-pilgrim 0.4.0 (liberation-data/pi-pilgrim#10) adds
AsyncPilgrimAssembly, for an assembly whose teardown is async. Itsclose()is a nativeasync defthat awaitsaclose(), and itswithrefuses. It closes held and owned child assemblies through their own lifecycle. It also addsAsyncTeardownRequired, aPilgrimError.>=0.4.0,<0.5, and the lock is updated.DrivineAssemblysubclassesAsyncPilgrimAssembly. Soawait close(),asyncio.run(close()),await aclose()andasync withall close it, whether or not the registry was made. An application assembly closes it whether it holds it withAssemblyHolder.shared(DrivineAssembly)or as a component,self.shared(DrivineAssembly). A sync close of either assembly closes Drivine while it has no registry. Once Drivine has a registry, that sync close refuses withAsyncTeardownRequiredbefore closing anything. A subclass ofDrivineAssemblythat overridesaclose()refuses a sync close from the start, since its own teardown is async.with DrivineAssembly()(async) raisesAsyncTeardownRequired.DrivineAssemblyoverrides only__enter__, so that the refusal also points todrivine.sync.DrivineAssembly.__exit__is pi-pilgrim's.PilgrimAssembly, anddrivine/sync/drivine_assembly.pyis byte for byte the same as on main.scripts/unasync.pymapsAsyncPilgrimAssemblytoPilgrimAssembly. ItsASYNC_ONLYtable leavesDrivineAssembly.__enter__out of the sync code, and that's the only entry it has.docs/09-with-pi-pilgrim.mdsays that the async assembly is anAsyncPilgrimAssemblyand lists what closes it. Its "Upgrading from 0.2.0" section is updated to match.docs/design.mdsays the same.One behaviour to know about:
close()called withoutawaitcloses nothing, even with no registry made, and Python warns that a coroutine was never awaited. That's how a native coroutine behaves, and the docs say to await it.Tests
In
tests/unit/test_assembly_lifecycle.py, which passes under-W error:DrivineAssemblyis anAsyncPilgrimAssembly, and the sync one isn't.await close()ends the providers, and the assembly makes no more components. Calling it twice, or afteraclose(), ends them only once. With no registry made, it closes the assembly.asyncio.run(close())closes it, with or without a registry.close()left unawaited closes nothing and warns, with or without a registry.self.shared): a sync close closes a Drivine with no registry. Once Drivine has a registry, the sync close refuses withAsyncTeardownRequired, leaves everything open, andaclose()then closes it.await aclose()on the holder closes Drivine.AssemblyHolder.shared(DrivineAssembly), thenawait app.drivine.close(). The application assembly's syncclose()closes a Drivine with no registry, and refuses once Drivine has one.await AssemblyHolder.aclose()closes it.withon the async assembly raisesAsyncTeardownRequired, and the message names the sync API.close()still closes and returnsNone.drivine4j and Drivine for TypeScript have no
DrivineAssembly, so there's nothing to port.aclose():await close()runs the override, and a sync close refuses even with no registry.test_await_close_ends_every_provider_when_one_fails).tests/unit/test_unasync.py:ASYNC_ONLYleaves out exactly the definitions it names, and refuses a name the module doesn't define.