@@ -624,7 +624,7 @@ class Flow:
624624
625625 _name : str
626626 _full_name : str
627- _lazy_engine_flow : Callable [[], _engine .Flow ]
627+ _lazy_engine_flow : Callable [[], _engine .Flow ] | None
628628
629629 def __init__ (
630630 self , name : str , full_name : str , engine_flow_creator : Callable [[], _engine .Flow ]
@@ -664,18 +664,18 @@ def build_tree(label: str, lines: list[Any]) -> Tree:
664664 return tree
665665
666666 def _get_spec (self , verbose : bool = False ) -> _engine .RenderedSpec :
667- return self ._lazy_engine_flow ().get_spec (
667+ return self .internal_flow ().get_spec (
668668 output_mode = "verbose" if verbose else "concise"
669669 )
670670
671671 def _get_schema (self ) -> list [tuple [str , str , str ]]:
672- return cast (list [tuple [str , str , str ]], self ._lazy_engine_flow ().get_schema ())
672+ return cast (list [tuple [str , str , str ]], self .internal_flow ().get_schema ())
673673
674674 def __str__ (self ) -> str :
675675 return str (self ._get_spec ())
676676
677677 def __repr__ (self ) -> str :
678- return repr (self ._lazy_engine_flow ())
678+ return repr (self .internal_flow ())
679679
680680 @property
681681 def name (self ) -> str :
@@ -715,12 +715,14 @@ def evaluate_and_dump(
715715 """
716716 Evaluate the flow and dump flow outputs to files.
717717 """
718- return self ._lazy_engine_flow ().evaluate_and_dump (dump_engine_object (options ))
718+ return self .internal_flow ().evaluate_and_dump (dump_engine_object (options ))
719719
720720 def internal_flow (self ) -> _engine .Flow :
721721 """
722722 Get the engine flow.
723723 """
724+ if self ._lazy_engine_flow is None :
725+ raise RuntimeError (f"Flow { self .full_name } is already removed" )
724726 return self ._lazy_engine_flow ()
725727
726728 async def internal_flow_async (self ) -> _engine .Flow :
@@ -731,27 +733,32 @@ async def internal_flow_async(self) -> _engine.Flow:
731733
732734 def setup (self , report_to_stdout : bool = False ) -> None :
733735 """
734- Setup the flow.
736+ Setup persistent backends of the flow.
735737 """
736738 execution_context .run (self .setup_async (report_to_stdout = report_to_stdout ))
737739
738740 async def setup_async (self , report_to_stdout : bool = False ) -> None :
739741 """
740- Setup the flow. The async version.
742+ Setup persistent backends of the flow. The async version.
741743 """
742744 await make_setup_bundle ([self ]).describe_and_apply_async (
743745 report_to_stdout = report_to_stdout
744746 )
745747
746748 def drop (self , report_to_stdout : bool = False ) -> None :
747749 """
748- Drop the flow.
750+ Drop persistent backends of the flow.
751+
752+ The current instance is still valid after it's called.
753+ For example, you can still call `setup()` after it, to setup the persistent backends again.
754+
755+ Call `cocoindex.remove_flow()` if you want to remove the flow from the current process.
749756 """
750757 execution_context .run (self .drop_async (report_to_stdout = report_to_stdout ))
751758
752759 async def drop_async (self , report_to_stdout : bool = False ) -> None :
753760 """
754- Drop the flow. The async version.
761+ Drop persistent backends of the flow. The async version.
755762 """
756763 await make_drop_bundle ([self ]).describe_and_apply_async (
757764 report_to_stdout = report_to_stdout
@@ -805,6 +812,19 @@ def add_flow_def(name: str, fl_def: Callable[[FlowBuilder, DataScope], None]) ->
805812 return fl
806813
807814
815+ def remove_flow (fl : Flow ) -> None :
816+ """
817+ Remove a flow from the current process to free up resources.
818+ After it's called, methods of the flow should no longer be called.
819+
820+ This will NOT touch the persistent backends of the flow.
821+ """
822+ _engine .remove_flow_context (fl .full_name )
823+ fl ._lazy_engine_flow = None # pylint: disable=protected-access
824+ with _flows_lock :
825+ del _flows [fl .name ]
826+
827+
808828def flow_def (
809829 name : str | None = None ,
810830) -> Callable [[Callable [[FlowBuilder , DataScope ], None ]], Flow ]:
0 commit comments