Sington provider with setup and teardown methods?
How can I create a Singleton object based on a generator?
For example
def session_factory(connection):
with connection() as conn:
session = Session(bind=conn)
yield session
try:
session.commit()
except:
session.rollback()
finally:
session.close()
class Container(containers.DeclarativeContainer):
session = providers.ThreadLocalSingleton(session_factory, connection=...)
Hi @rollo-b2c2 , take a look on https://python-dependency-injector.ets-labs.org/providers/resource.html
The problem is with a resource is that it's a global, once it's instantiated it's there until someone shuts it down.
How is that different behaviour from your description in the issue?
I'm looking at the same situation when trying to open DB session per FastAPI request by using Resource provider.
As a base I've used example from docs and added resource with:
def get_database_session(database_session_factory: Database.session):
with database_session_factory() as database_session:
yield database_session
database_session = Resource(
get_database_session,
database_session_factory=database.provided.session,
)
Issue with this code is that database session is only opened once (on first request) then object is stored globally and server for every consecutive request. I'm also noticing that session is never closed, I guess because generator is not called for the 2nd time.
It seems like some hybrid between Factory (executes on every request) and Resource (supports yield and doesn't need a class) provider would do the job? Was looking through docs and fiddling with it but it seems like there is no appropriate provider available, did I miss any?
I think this issue may also be related to https://github.com/ets-labs/python-dependency-injector/issues/495.
I'm trying to do the same thing but still struggling.
It works if we inject the Resource in the route, using the Closing marker.
For example:
# containers.py
def get_session(session_factory):
with session_factory() as session:
logging.warning("Started session")
yield session
logging.warning("Ended session")
class Container(containers.DeclarativeContainer):
db = providers.Singleton(Database, db_url=config.db.url)
session = providers.Resource(get_session, session_factory=db.provided.session)
my_repository = providers.Factory(WorkflowRepository, session=session)
my_service = providers.Factory(MyService, my_repository=my_repository)
# Flask route
@bp.route("/", methods=["GET"])
@inject
def more(db_session: Session = Closing[Provide[Container.session]], my_service: MyService = Provide[Container.my_service]):
return my_service.execute("something")
I'm not sure if it's working the way I imagine it is, but it seems to work.