Hey all, I'm upgrading to the new AsyncBuilder/Asy...
# hamilton-help
r
Hey all, I'm upgrading to the new AsyncBuilder/AsyncDriver and wondering if I'm correctly setting the
result_builder
. With the regular Builder I would normally set it using
with_adapters()
, e.g.:
Copy code
result_builder = base.PandasDataFrameResult()
await AsyncBuilder().with_config(self.config).with_modules(*self.included_modules).with_adapters(result_builder).build()
but this raises
ValueError("You cannot pass more than one result builder to the async driver. Please pass in a single result builder")
here: https://github.com/DAGWorks-Inc/hamilton/blob/main/hamilton/async_driver.py#L225-L229 Looks like that is due to a default DictResult getting set if the
AsyncBuilder.result_builder
is None: https://github.com/DAGWorks-Inc/hamilton/blob/main/hamilton/async_driver.py#L478-L480 I'm able to work around it by setting the builder's
result_builder
attr before calling
build()
, but not sure if that is the intended usage:
Copy code
result_builder = base.PandasDataFrameResult()
builder = AsyncBuilder().with_config(self.config).with_modules(*self.included_modules)
builder.result_builder = result_builder
await builder.build()
e
Hey — yes, good question. Right now I’m thinking this is a bug — and you debugged it basically, thanks! I’m going to repro/make sure I’ve mentally modeled this correctly, then see if there’s a fix. It was intended to capture the result builder from the list of adapters but I think I missed that… Thanks! Opened up this issue to track: https://github.com/DAGWorks-Inc/hamilton/issues/1022
r
Ok cool, thanks! Something else I'm working through, I've always initialized the builder/driver deep into some sync code. Since
AsyncBuilder.build
is async, it means I'd have to break my encapsulation and have parent async components (e.g. fastapi app) call down through to build the driver asynchronously. Would it be possible to add a non-async version of
build
? Or would that not play well with potential async lifecycle adapters? Alternative is maybe I manually build
AsyncDriver
without the builder for now
e
Hmm, interesting. I think this is just generally a problem with sync/async. It often kills encapsulation and doesn’t translate between them. You’ve got it right that it can mess with lifecycle adapters, but these are just the async initialization ones, and you can always call
.ainit()
later. My standard approach is to add “shadow methods” (E.G. those that start with
a
) to your call chain, rather than messing around with
asyncio.run
(which is possible but risky). There are trade-offs (it often involves some duplicated code), but it’s kept me pretty sane. Then I’ll instantiate it in the lifespan method: https://github.com/DAGWorks-Inc/hamilton/blob/main/examples/async/fastapi_example.py#L33. If that’s not feasible, then here are some workarounds, but I think it would be reasonable to have a non-init power-user method. Can scope that out shortly, and see if I like it/add to the next minor release. So yeah, for now I think your solution is OK for now but here are some ideas: Some workarounds: 1. Instantiate it directly without calling
.ainit
(probably a good approach for now) 2. Use asynio.run() (nasty, TBH, but it can work sometimes) 3. Subclass with a
non_init_build()
function that just does everything in these functions (also not ideal)
r
Awesome, thanks! Yeah always a pain trying to mix sync/async. I'll keep poking around but think I can work around it with one of these methods, or just deferring the async driver creation until my first async execute call when I already have the async context
e
Great, yeah, I think it’s quite reasonable to add a non-initializing build as well
r
Semi-related, I just opened this issue for the AsyncDriver: https://github.com/DAGWorks-Inc/hamilton/issues/1023 It seems like a small fix, so I'll see if I can contribute it soon but you guys might beat me to it
e
Nice find! Yes this is great. Yes, would love a contribution, will comment
👍 1
Hey — so I’m working on these, I can probably take a step at all three (I imagine you haven’t already started on the contribution). If I get you an RC version will you be able to test it out?
(happy to release a patch version too, but will hold off on a minor release until our next cut from main for the new non-async method)
r
Nice, yeah! Happy to test out a RC
e
Yep! Will ping when I have something.
🙌 1
@Ryan Whitten give
sf-hamilton==1.71.0rc0
a try? Happened to have a few minutes to hammer it out. The new function is
build_without_init
which gives you a non-initialized async driver. Up to you to initialize (recommend it), even though you might not be using those that are required to get initialized. Should have fixes for the other issues as well!
r
Awesome, tested out all 3 changes and everything looks good!
e
Great! Will queue this up in the next release if that’s OK — RC version works till next week?
r
Yeah that would be great, thanks for the quick fixes!
🫡 1
e
Yep thanks for the feedback/bug finds!
💯 1