@@ -42,15 +42,43 @@ def valid_output_file(value: str | None) -> str | None:
4242 """Validate output file has supported extension."""
4343 if value is None :
4444 return None
45- parts = value . split ( "." )
46- ext = f". { parts [ - 1 ] .lower ()} "
47- if len ( parts ) < 2 :
45+ path = Path ( value )
46+ ext = path . suffix .lower ()
47+ if not ext :
4848 raise typer .BadParameter (f"Output file must have an extension. { VALID_MSG } " )
4949 if ext not in VALID_EXTENSIONS :
5050 raise typer .BadParameter (f"Unsupported extension '{ ext } '. { VALID_MSG } " )
5151 return value
5252
5353
54+ def valid_batch_pattern (value : str ) -> str :
55+ """Validate batch output pattern has exactly one {} placeholder and a valid extension."""
56+ try :
57+ example_file = value .format (0 )
58+ # Validate file extension
59+ valid_output_file (example_file )
60+ except (IndexError , KeyError ) as e :
61+ raise typer .BadParameter (
62+ f"Invalid output pattern '{ value } '. Must contain exactly one {{}} placeholder"
63+ ) from e
64+ return value
65+
66+
67+ def valid_rename_mapping (value : str ) -> str :
68+ """Validate rename mapping format is 'old:new,old2:new2'."""
69+ for pair in value .split ("," ):
70+ parts = pair .strip ().split (":" )
71+ if len (parts ) != 2 :
72+ raise typer .BadParameter (
73+ f"Invalid mapping '{ pair .strip ()} '. Expected format: 'old:new,old2:new2'"
74+ )
75+ if not parts [0 ].strip () or not parts [1 ].strip ():
76+ raise typer .BadParameter (
77+ f"Invalid mapping '{ pair .strip ()} '. Column names cannot be empty"
78+ )
79+ return value
80+
81+
5482def _parse_columns (columns : str ) -> list [str ]:
5583 """Parse a comma-separated string of column names into a list."""
5684 return [col .strip () for col in columns .split ("," )]
0 commit comments