Replies: 4 comments
-
@chrisk314 Hi! In order to finalize resource you need to call DI.tear_down() await DI.tear_down() If you want to finalize after each call of require_resource, you can try using ContextResource |
Beta Was this translation helpful? Give feedback.
-
@lesnik512 I think we were a little pre-mature with converting this to a discussion. I have analyzed the issue and can reproduce this behavior. Indeed, similar behavior exists on
Quick SolutionI see that in the example all the code is sync and I have realized we did not expose the say_hello_goodbye._context.sync_tear_down() This will also make the finalization debuggable :) Another solution:I would recommend using a Let us know if this helps. |
Beta Was this translation helpful? Give feedback.
-
@alexanderlazarev0 thank you for looking into this and providing a detailed explanation and possible solutions. Much appreciated. It makes sense that there should be some tear down to ensure the iterator is invoked again to evaluate the finally block. I guess the inconsistency between running in debug mode or not is, as you say, due to differences in how code is executed, reference counted, and garbage collected etc; therefore not something to be relied upon. One comment I would add is that the existence of the I will look into the In my case, the DI container is being used in a python library. I'm creating the DI container in a Perhaps there is a solution involving keeping a reference to a |
Beta Was this translation helpful? Give feedback.
-
Thank you for the feedback, we have been working on our documentation, unfortunately we haven't gotten to these providers yet. I have now hopefully addressed the documentation issues in #161, so the documentation should be better with the next release. I have also implemented sync tear down logic for relevant providers in #161 so now the intended way to finalize Container.sync_resource.sync_tear_down() # as of that-depends>=2.1.0
I hope I have understood your use case correctly, so here are some examples: Table of Contents
File: lib/di.pyimport typing
from datetime import datetime
from that_depends import BaseContainer, providers
def create_sync_resource() -> typing.Iterator[datetime]:
print("Initiating sync resource")
yield datetime.now()
print("Destructing sync resource")
class Container(BaseContainer):
"""Container for the application."""
default_scope = None
context_resource = providers.ContextResource(create_sync_resource)
another_context_resource = providers.ContextResource(create_sync_resource)
resource = providers.Resource(create_sync_resource) File: lib/entry.pyfrom datetime import datetime
from lib.di import Container
from that_depends import Provide, container_context, inject
@Container.context_resource.context
def entry_point_with_wrapper() -> None:
library_code_with_context_resource()
def entry_point_with_explicit() -> None:
with Container.context_resource.sync_context():
library_code_with_context_resource()
@container_context(Container.context_resource, Container.another_context_resource) # make sure `that-depends>=2.1.1`
def entry_with_multiple_resources_wrapped() -> None:
library_code_with_context_resource()
def entry_with_multiple_resources_explicit() -> None:
with container_context(Container.context_resource, Container.another_context_resource):
# this will only call initialization and finalization of `another_context_resource` if it actually
# gets used in the rest of the code
library_code_with_context_resource()
def entry_with_multiple_resources_container() -> None:
with Container.sync_context():
library_code_with_context_resource()
def entry_point_with_resource() -> None:
library_code_with_resource()
Container.resource.sync_tear_down()
@inject
def library_code_with_context_resource(time: datetime = Provide[Container.context_resource]) -> None:
print(time)
@inject
def library_code_with_resource(time: datetime = Provide[Container.resource]) -> None:
print(time) File: main.pyfrom lib.entry import (
entry_point_with_explicit,
entry_point_with_resource,
entry_point_with_wrapper,
entry_with_multiple_resources_explicit,
entry_with_multiple_resources_wrapped, entry_with_multiple_resources_container,
)
def calling_code() -> None:
entry_point_with_wrapper()
entry_point_with_explicit()
entry_point_with_resource()
entry_with_multiple_resources_wrapped()
entry_with_multiple_resources_explicit()
entry_with_multiple_resources_container()
if __name__ == "__main__":
calling_code() You can also achieve similar behavior with scopes
I would recommend avoiding any kind of logic related to |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi, I'm seeing some strange behaviour when attempting to use
Resource
type providers during debug sessions in VS Code. From adding both print statements and breakpoints into the code, it's clear that the code in thefinally
block is never reached when running in debug mode in VS Code. Running the code normally, i.e., as a python script in a terminal, I can see the print outputs as expected.There is a minimal reproducible example below. In this case, it's not an issue; however the actual code where I noticed this problem launches a child process which must be terminated in the
finally
section (it runs an infinte loop - it's a message proxy). Failure to evaluate this finally block in VS Code debug mode causes test cases to run indefinitely. I can add similar code into a pytest conftest fixture and it works fine. It's worth mentioning that running the script inside VS Code but not in debug mode also works fine.I'm running...
python: 3.12.8
that-depends: 1.27.0
vs code: 197.0
os: Windows 11 with WSL2 Ubuntu 24.04
VS Code launch config for convenience.
Beta Was this translation helpful? Give feedback.
All reactions