77"""
88import sys
99import warnings
10+ from typing import Optional
1011
1112# Suppress urllib3 NotOpenSSLWarning on systems with LibreSSL
1213warnings .filterwarnings (
1819import typer # noqa: E402
1920
2021import dashscope # noqa: E402
22+ from dashscope .cli .common import err_console # noqa: E402
23+ from dashscope .common .error import AuthenticationError # noqa: E402
2124from dashscope .cli import ( # noqa: E402
25+ application ,
26+ code_generation ,
2227 deployments ,
28+ embeddings ,
2329 files ,
2430 fine_tunes ,
2531 generation ,
32+ image_generation ,
33+ image_synthesis ,
34+ models ,
35+ multimodal_conversation ,
36+ multimodal_embedding ,
2637 oss ,
38+ rerank ,
39+ speech_synthesis ,
40+ tokenization ,
41+ transcription ,
42+ understanding ,
43+ video_synthesis ,
2744)
2845
2946
6986 "--page_size" : "--page-size" ,
7087}
7188
89+ _TOP_LEVEL_COMMANDS = {
90+ "generation" ,
91+ "ft" ,
92+ "fine-tunes" ,
93+ "files" ,
94+ "deployments" ,
95+ "oss" ,
96+ "rerank" ,
97+ "embeddings" ,
98+ "tokenization" ,
99+ "models" ,
100+ "understanding" ,
101+ "application" ,
102+ "code-generation" ,
103+ "image-synthesis" ,
104+ "video-synthesis" ,
105+ "image-generation" ,
106+ "multimodal-conversation" ,
107+ "multimodal-embedding" ,
108+ "transcription" ,
109+ "speech-synthesis" ,
110+ "rl" ,
111+ "agentic-rl" ,
112+ }
113+
114+
115+ _COMMANDS_WITH_LOCAL_API_KEY = {"oss" , "rl" , "agentic-rl" }
116+ _LEGACY_COMMANDS_WITH_SIZE_OPTION = {
117+ "files.list" ,
118+ "fine_tunes.list" ,
119+ "deployments.list" ,
120+ }
121+
122+
123+ def _translate_param_name (arg ):
124+ """Translate legacy underscore option names to Typer hyphen names."""
125+ if arg in _PARAM_MAP :
126+ return _PARAM_MAP [arg ]
127+ if arg .startswith ("--" ) and "=" in arg :
128+ option_name , option_value = arg .split ("=" , 1 )
129+ if option_name in _PARAM_MAP :
130+ return f"{ _PARAM_MAP [option_name ]} ={ option_value } "
131+ return arg
132+
72133
73134def _translate_legacy_args (argv ):
74135 """Translate legacy argparse command format to Typer format.
@@ -81,59 +142,95 @@ def _translate_legacy_args(argv):
81142 if len (argv ) < 2 :
82143 return argv
83144
84- new_argv = [argv [0 ]] # Keep program name
85- i = 1
86-
87- # Check if first arg is a legacy command
88- if i < len (argv ) and argv [i ] in _COMMAND_MAP :
89- # Split "fine_tunes.call" into ["fine-tunes", "call"]
90- new_cmd = _COMMAND_MAP [argv [i ]].split ()
91- new_argv .extend (new_cmd )
92- i += 1
145+ is_legacy_command = argv [1 ] in _COMMAND_MAP
146+ if not is_legacy_command :
147+ return [argv [0 ]] + [_translate_param_name (arg ) for arg in argv [1 :]]
93148
94- # Process remaining args
149+ command_args = _COMMAND_MAP [argv [1 ]].split ()
150+ top_level_args = []
151+ translated_args = []
152+ i = 2
95153 while i < len (argv ):
96154 arg = argv [i ]
97-
98- # Translate parameter names
99- if arg in _PARAM_MAP :
100- new_argv .append (_PARAM_MAP [arg ])
101- elif arg .startswith ("--" ) and "=" in arg :
102- opt , val = arg .split ("=" , 1 )
103- if opt in _PARAM_MAP :
104- new_argv .append (f"{ _PARAM_MAP [opt ]} ={ val } " )
155+ translated_arg = _translate_param_name (arg )
156+ if argv [1 ] in _LEGACY_COMMANDS_WITH_SIZE_OPTION :
157+ if translated_arg == "--page-size" :
158+ translated_arg = "--size"
159+ elif translated_arg .startswith ("--page-size=" ):
160+ translated_arg = translated_arg .replace (
161+ "--page-size=" ,
162+ "--size=" ,
163+ 1 ,
164+ )
165+
166+ if translated_arg == "--api-key" :
167+ top_level_args .append ("--api-key" )
168+ if i + 1 < len (argv ):
169+ top_level_args .append (argv [i + 1 ])
170+ i += 2
105171 else :
106- new_argv .append (arg )
107- else :
108- new_argv .append (arg )
172+ i += 1
173+ continue
109174
175+ if translated_arg .startswith ("--api-key=" ):
176+ top_level_args .append (translated_arg )
177+ i += 1
178+ continue
179+
180+ translated_args .append (translated_arg )
110181 i += 1
111182
112- return new_argv
183+ return [argv [0 ]] + top_level_args + command_args + translated_args
184+
185+
186+ def _exit_missing_api_key_value (option_name ):
187+ err_console .print (
188+ f"[red]Error:[/red] Option '{ option_name } ' requires an argument." ,
189+ )
190+ sys .exit (2 )
113191
114192
115193def _extract_global_api_key (argv ):
116194 """Extract global -k/--api-key from argv and set dashscope.api_key.
117195
118- Returns modified argv with api-key args removed.
196+ For backward compatibility, global api-key can appear before or after most
197+ command names. Commands that define their own local api-key option are left
198+ untouched once their command name has been reached.
119199 """
120200 new_argv = []
121201 i = 0
202+ current_command = None
122203 while i < len (argv ):
123204 arg = argv [i ]
124205
125- # Check for -k or --api-key
206+ if i > 0 and current_command is None and arg in _TOP_LEVEL_COMMANDS :
207+ current_command = arg
208+
209+ should_parse_global_api_key = (
210+ current_command not in _COMMANDS_WITH_LOCAL_API_KEY
211+ )
212+
126213 if arg in ("-k" , "--api-key" ):
127- # Next arg should be the key value
128- if i + 1 < len (argv ):
129- dashscope .api_key = argv [i + 1 ]
130- i += 2 # Skip both -k and the value
214+ if i + 1 >= len (argv ):
215+ _exit_missing_api_key_value (arg )
216+ next_arg = argv [i + 1 ]
217+ if not next_arg or next_arg .startswith ("-" ):
218+ _exit_missing_api_key_value (arg )
219+ if should_parse_global_api_key :
220+ if next_arg in _TOP_LEVEL_COMMANDS :
221+ _exit_missing_api_key_value (arg )
222+ dashscope .api_key = next_arg
223+ i += 2
224+ continue
225+
226+ if arg .startswith ("--api-key=" ):
227+ api_key = arg .split ("=" , 1 )[1 ]
228+ if not api_key :
229+ _exit_missing_api_key_value ("--api-key" )
230+ if should_parse_global_api_key :
231+ dashscope .api_key = api_key
232+ i += 1
131233 continue
132- elif arg .startswith ("--api-key=" ):
133- # Handle --api-key=value format
134- dashscope .api_key = arg .split ("=" , 1 )[1 ]
135- i += 1
136- continue
137234
138235 new_argv .append (arg )
139236 i += 1
@@ -153,13 +250,42 @@ def _extract_global_api_key(argv):
153250 rich_markup_mode = "rich" ,
154251)
155252
253+
254+ @app .callback ()
255+ def callback (
256+ api_key : Optional [str ] = typer .Option (
257+ None ,
258+ "-k" ,
259+ "--api-key" ,
260+ help = "DashScope API Key." ,
261+ ),
262+ ):
263+ """Configure global CLI options."""
264+ if api_key :
265+ dashscope .api_key = api_key
266+
267+
156268# Register sub-command groups
157269app .add_typer (generation .app )
158270app .add_typer (fine_tunes .app , name = "ft" )
159271app .add_typer (fine_tunes .app , name = "fine-tunes" , hidden = True )
160272app .add_typer (files .app )
161273app .add_typer (deployments .app )
162274app .add_typer (oss .app )
275+ app .add_typer (rerank .app )
276+ app .add_typer (embeddings .app )
277+ app .add_typer (tokenization .app )
278+ app .add_typer (models .app )
279+ app .add_typer (understanding .app )
280+ app .add_typer (application .app )
281+ app .add_typer (code_generation .app )
282+ app .add_typer (image_synthesis .app )
283+ app .add_typer (video_synthesis .app )
284+ app .add_typer (image_generation .app )
285+ app .add_typer (multimodal_conversation .app )
286+ app .add_typer (multimodal_embedding .app )
287+ app .add_typer (transcription .app )
288+ app .add_typer (speech_synthesis .app )
163289
164290
165291def _register_rl_app ():
@@ -176,24 +302,41 @@ def _register_rl_app():
176302 name = "rl" ,
177303 help = "🚀 Agentic RL fine-tuning commands" ,
178304 )
179- except ImportError :
180- pass
181- except Exception :
182- pass
305+ app .add_typer (
306+ rl_app ,
307+ name = "agentic-rl" ,
308+ help = "🚀 Agentic RL fine-tuning commands" ,
309+ hidden = True ,
310+ )
311+ except ImportError as exception :
312+ err_console .print (
313+ "[yellow]Warning:[/yellow] Failed to register rl command: "
314+ f"{ exception } " ,
315+ )
316+ except Exception as exception :
317+ err_console .print (
318+ "[yellow]Warning:[/yellow] Failed to register rl command: "
319+ f"{ exception } " ,
320+ )
183321
184322
185323_register_rl_app ()
186324
187325
188326def main ():
189327 """Entry point for the ``dashscope`` console script."""
190- # Extract global api-key parameter FIRST
191- argv = _extract_global_api_key (sys .argv )
328+ # Translate legacy command format first so legacy --api_key can be treated
329+ # as the global --api-key option.
330+ argv = _translate_legacy_args (sys .argv )
192331
193- # Then translate legacy command format
194- argv = _translate_legacy_args (argv )
332+ # Extract global api-key parameter after legacy argument normalization.
333+ argv = _extract_global_api_key (argv )
195334
196335 # Update sys.argv for Typer
197336 sys .argv = argv
198337
199- app ()
338+ try :
339+ app ()
340+ except AuthenticationError as exception :
341+ err_console .print (f"[red]Error:[/red] { exception } " )
342+ sys .exit (1 )
0 commit comments