1010
1111from pipelex import log , pretty_print
1212from pipelex .exceptions import PipelexCLIError , PipelexConfigError
13- from pipelex .hub import get_pipe_provider
13+ from pipelex .hub import get_pipe_provider , get_pipeline_tracker , get_required_pipe
1414from pipelex .libraries .library_config import LibraryConfig
15- from pipelex .pipe_works .pipe_dry import dry_run_all_pipes
15+ from pipelex .pipe_works .pipe_dry import dry_run_all_pipes , dry_run_single_pipe
1616from pipelex .pipelex import Pipelex
1717from pipelex .tools .config .manager import config_manager
1818
1919
20+ def is_pipelex_libraries_folder (folder_path : str ) -> bool :
21+ """Check if the given folder path contains a valid pipelex libraries structure.
22+
23+ A valid pipelex libraries folder should contain the following subdirectories:
24+ - pipelines
25+ - llm_deck
26+ - llm_integrations
27+ - plugins
28+ - templates
29+
30+ Args:
31+ folder_path: Path to the folder to check
32+
33+ Returns:
34+ True if the folder contains all required subdirectories, False otherwise
35+ """
36+ if not os .path .exists (folder_path ) or not os .path .isdir (folder_path ):
37+ return False
38+
39+ required_subdirs = ["pipelines" , "llm_deck" , "llm_integrations" , "plugins" , "templates" ]
40+
41+ for subdir in required_subdirs :
42+ subdir_path = os .path .join (folder_path , subdir )
43+ if not os .path .exists (subdir_path ) or not os .path .isdir (subdir_path ):
44+ return False
45+
46+ return True
47+
48+
2049class PipelexCLI (TyperGroup ):
2150 @override
2251 def get_command (self , ctx : Context , cmd_name : str ) -> Optional [Command ]:
@@ -38,22 +67,31 @@ def get_command(self, ctx: Context, cmd_name: str) -> Optional[Command]:
3867
3968@app .command ("init-libraries" )
4069def init_libraries (
70+ directory : Annotated [str , typer .Argument (help = "Directory where to create the pipelex_libraries folder" )] = "." ,
4171 overwrite : Annotated [bool , typer .Option ("--overwrite" , "-o" , help = "Warning: If set, existing files will be overwritten." )] = False ,
4272) -> None :
43- """Initialize pipelex libraries in the current directory.
73+ """Initialize pipelex libraries in a pipelex_libraries folder in the specified directory.
4474
4575 If overwrite is False, only create files that don't exist yet.
4676 If overwrite is True, all files will be overwritten even if they exist.
4777 """
4878 try :
49- # TODO: Have a more proper print message regarding the overwrited files (e.g. list of files that were overwritten or not)
50- LibraryConfig ().export_libraries (overwrite = overwrite )
79+ # Always create a pipelex_libraries folder in the specified directory
80+ target_path = os .path .join (directory , "pipelex_libraries" )
81+
82+ # Create the target directory if it doesn't exist
83+ os .makedirs (directory , exist_ok = True )
84+
85+ # Create a LibraryConfig instance with the target path
86+ library_config = LibraryConfig (config_folder_path = target_path )
87+ library_config .export_libraries (overwrite = overwrite )
88+
5189 if overwrite :
52- typer .echo (" Successfully initialized pipelex libraries (all files overwritten)" )
90+ typer .echo (f"✅ Successfully initialized pipelex libraries at ' { target_path } ' (all files overwritten)" )
5391 else :
54- typer .echo (" Successfully initialized pipelex libraries (only created non-existing files)" )
92+ typer .echo (f"✅ Successfully initialized pipelex libraries at ' { target_path } ' (only created non-existing files)" )
5593 except Exception as e :
56- raise PipelexCLIError (f"Failed to initialize libraries: { e } " )
94+ raise PipelexCLIError (f"Failed to initialize libraries at ' { directory } ' : { e } " )
5795
5896
5997@app .command ("init-config" )
@@ -79,17 +117,49 @@ def init_config(
79117def validate (
80118 relative_config_folder_path : Annotated [
81119 str , typer .Option ("--config-folder-path" , "-c" , help = "Relative path to the config folder path" )
82- ] = "pipelex_libraries" ,
120+ ] = "./ pipelex_libraries" ,
83121) -> None :
84122 """Run the setup sequence."""
85- config_folder_path = os .path .join (os .getcwd (), relative_config_folder_path )
86- LibraryConfig (config_folder_path = config_folder_path ).export_libraries ()
123+ # Check if pipelex libraries folder exists
124+ if not is_pipelex_libraries_folder (relative_config_folder_path ):
125+ typer .echo (f"❌ No pipelex libraries folder found at '{ relative_config_folder_path } '" )
126+ typer .echo ("To create a pipelex libraries folder, run: pipelex init-libraries" )
127+ raise typer .Exit (1 )
128+
87129 pipelex_instance = Pipelex .make (relative_config_folder_path = relative_config_folder_path , from_file = False )
88130 pipelex_instance .validate_libraries ()
89131 asyncio .run (dry_run_all_pipes ())
90132 log .info ("Setup sequence passed OK, config and pipelines are validated." )
91133
92134
135+ @app .command ()
136+ def dry_run_pipe (
137+ pipe_code : Annotated [str , typer .Argument (help = "The pipe code to dry run" )],
138+ relative_config_folder_path : Annotated [
139+ str , typer .Option ("--config-folder-path" , "-c" , help = "Relative path to the config folder path" )
140+ ] = "./pipelex_libraries" ,
141+ ) -> None :
142+ """Dry run a single pipe."""
143+ # Check if pipelex libraries folder exists
144+ if not is_pipelex_libraries_folder (relative_config_folder_path ):
145+ typer .echo (f"❌ No pipelex libraries folder found at '{ relative_config_folder_path } '" )
146+ typer .echo ("To create a pipelex libraries folder, run: pipelex init-libraries" )
147+ raise typer .Exit (1 )
148+
149+ try :
150+ # Initialize Pipelex
151+ pipelex_instance = Pipelex .make (relative_config_folder_path = relative_config_folder_path , from_file = False )
152+ pipelex_instance .validate_libraries ()
153+
154+ # Run the single pipe dry run
155+ asyncio .run (dry_run_single_pipe (pipe_code ))
156+ get_pipeline_tracker ().output_flowchart ()
157+
158+ except Exception as e :
159+ typer .echo (f"❌ Error running dry run for pipe '{ pipe_code } ': { e } " )
160+ raise typer .Exit (1 )
161+
162+
93163@app .command ()
94164def show_config () -> None :
95165 """Show the pipelex configuration."""
@@ -116,6 +186,22 @@ def list_pipes(
116186 raise PipelexCLIError (f"Failed to list pipes: { e } " )
117187
118188
189+ @app .command ("show-pipe" )
190+ def show_pipe (
191+ pipe_code : Annotated [
192+ str ,
193+ typer .Argument (help = "Pipeline code to show definition for" ),
194+ ],
195+ relative_config_folder_path : Annotated [
196+ str , typer .Option ("--config-folder-path" , "-c" , help = "Relative path to the config folder path" )
197+ ] = "./pipelex_libraries" ,
198+ ) -> None :
199+ """Show pipe from the pipe library."""
200+ Pipelex .make (relative_config_folder_path = relative_config_folder_path , from_file = False )
201+ pipe = get_required_pipe (pipe_code = pipe_code )
202+ pretty_print (pipe , title = f"Pipe '{ pipe_code } '" )
203+
204+
119205def main () -> None :
120206 """Entry point for the pipelex CLI."""
121207 app ()
0 commit comments