1
1
import json
2
2
import os
3
- import shutil
4
3
import sys
5
4
6
5
import click
13
12
from clarifai .utils .logging import logger
14
13
15
14
16
- # @click.group(cls=CustomMultiGroup)
17
15
@click .group (cls = AliasedGroup )
18
16
@click .version_option (version = __version__ )
19
17
@click .option ('--config' , default = DEFAULT_CONFIG )
@@ -54,42 +52,71 @@ def shell_completion(shell):
54
52
os .system (f"_CLARIFAI_COMPLETE={ shell } _source clarifai" )
55
53
56
54
57
- @cli .group (
58
- ['cfg' ],
59
- cls = AliasedGroup ,
60
- context_settings = {'max_content_width' : shutil .get_terminal_size ().columns - 10 },
61
- )
55
+ @cli .group (cls = AliasedGroup )
62
56
def config ():
63
- """Manage CLI configuration"""
57
+ """
58
+ Manage multiple configuration profiles (contexts).
59
+
60
+ Authentication Precedence:\n
61
+ 1. Environment variables (e.g., `CLARIFAI_PAT`) are used first if set.
62
+ 2. The settings from the active context are used if no environment variables are provided.\n
63
+ """
64
64
65
65
66
- @config .command (['e' ])
66
+ @cli .command ()
67
+ @click .argument ('api_url' , default = DEFAULT_BASE )
68
+ @click .option ('--user_id' , required = False , help = 'User ID' )
67
69
@click .pass_context
68
- def edit (ctx ):
69
- """Edit the configuration file """
70
- os . system ( f' { os . environ . get ( "EDITOR" , "vi" ) } { ctx . obj . filename } ' )
70
+ def login (ctx , api_url , user_id ):
71
+ """Login command to set PAT and other configurations. """
72
+ from clarifai . utils . cli import validate_context_auth
71
73
74
+ name = input ('context name (default: "default"): ' )
75
+ user_id = user_id if user_id is not None else input ('user id: ' )
76
+ pat = input_or_default (
77
+ 'personal access token value (default: "ENVVAR" to get out of env var rather than config): ' ,
78
+ 'ENVVAR' ,
79
+ )
72
80
73
- @config .command (['current' ])
74
- @click .option ('-o' , '--output-format' , default = 'name' , type = click .Choice (['name' , 'json' , 'yaml' ]))
75
- @click .pass_context
76
- def current_context (ctx , output_format ):
77
- """Get the current context"""
78
- if output_format == 'name' :
79
- print (ctx .obj .current_context )
80
- elif output_format == 'json' :
81
- print (json .dumps (ctx .obj .contexts [ctx .obj .current_context ].to_serializable_dict ()))
82
- else :
83
- print (yaml .safe_dump (ctx .obj .contexts [ctx .obj .current_context ].to_serializable_dict ()))
81
+ # Validate the Context Credentials
82
+ validate_context_auth (pat , user_id , api_url )
83
+
84
+ context = Context (
85
+ name ,
86
+ CLARIFAI_API_BASE = api_url ,
87
+ CLARIFAI_USER_ID = user_id ,
88
+ CLARIFAI_PAT = pat ,
89
+ )
90
+
91
+ if context .name == '' :
92
+ context .name = 'default'
93
+
94
+ ctx .obj .contexts [context .name ] = context
95
+ ctx .obj .current_context = context .name
96
+
97
+ ctx .obj .to_yaml ()
98
+ logger .info (
99
+ f"Login successful and Configuration saved successfully for context '{ context .name } '"
100
+ )
101
+
102
+
103
+ def pat_display (pat ):
104
+ return pat [:5 ] + "****"
105
+
106
+
107
+ def input_or_default (prompt , default ):
108
+ value = input (prompt )
109
+ return value if value else default
84
110
85
111
86
- @config .command (['list' , 'ls' ])
112
+ # Context management commands under config group
113
+ @config .command (aliases = ['get-contexts' , 'list-contexts' ])
87
114
@click .option (
88
115
'-o' , '--output-format' , default = 'wide' , type = click .Choice (['wide' , 'name' , 'json' , 'yaml' ])
89
116
)
90
117
@click .pass_context
91
118
def get_contexts (ctx , output_format ):
92
- """Get all contexts"""
119
+ """List all available contexts. """
93
120
if output_format == 'wide' :
94
121
columns = {
95
122
'' : lambda c : '*' if c .name == ctx .obj .current_context else '' ,
@@ -106,7 +133,6 @@ def get_contexts(ctx, output_format):
106
133
additional_columns .add (key )
107
134
for key in sorted (additional_columns ):
108
135
columns [key ] = lambda c , k = key : getattr (c , k ) if hasattr (c , k ) else ""
109
-
110
136
formatter = TableFormatter (
111
137
custom_columns = columns ,
112
138
)
@@ -123,101 +149,45 @@ def get_contexts(ctx, output_format):
123
149
print (yaml .safe_dump (dicts ))
124
150
125
151
126
- @config .command (['use' ])
127
- @click .argument ('context- name' , type = str )
152
+ @config .command (aliases = ['use-context ' ])
153
+ @click .argument ('name' , type = str )
128
154
@click .pass_context
129
- def use_context (ctx , context_name ):
130
- """Set the current context"""
131
- if context_name not in ctx .obj .contexts :
155
+ def use_context (ctx , name ):
156
+ """Set the current context. """
157
+ if name not in ctx .obj .contexts :
132
158
raise click .UsageError ('Context not found' )
133
- ctx .obj .current_context = context_name
159
+ ctx .obj .current_context = name
134
160
ctx .obj .to_yaml ()
135
- print (f'Set { context_name } as the current context' )
136
-
137
-
138
- @config .command (['cat' ])
139
- @click .option ('-o' , '--output-format' , default = 'yaml' , type = click .Choice (['yaml' , 'json' ]))
140
- @click .pass_obj
141
- def dump (ctx_obj , output_format ):
142
- """Dump the configuration to stdout"""
143
- if output_format == 'yaml' :
144
- yaml .safe_dump (ctx_obj .to_dict (), sys .stdout )
145
- else :
146
- json .dump (ctx_obj .to_dict (), sys .stdout , indent = 2 )
147
-
148
-
149
- @config .command (['cat' ])
150
- @click .pass_obj
151
- def env (ctx_obj ):
152
- """Print env vars. Use: eval "$(clarifai config env)" """
153
- ctx_obj .current .print_env_vars ()
161
+ print (f'Set { name } as the current context' )
154
162
155
163
156
- @cli .command ()
157
- @click .argument ('api_url' , default = DEFAULT_BASE )
158
- @click .option ('--user_id' , required = False , help = 'User ID' )
164
+ @config .command (aliases = ['current-context' ])
165
+ @click .option ('-o' , '--output-format' , default = 'name' , type = click .Choice (['name' , 'json' , 'yaml' ]))
159
166
@click .pass_context
160
- def login (ctx , api_url , user_id ):
161
- """Login command to set PAT and other configurations."""
162
- from clarifai .utils .cli import validate_context_auth
163
-
164
- name = input ('context name (default: "default"): ' )
165
- user_id = user_id if user_id is not None else input ('user id: ' )
166
- pat = input_or_default (
167
- 'personal access token value (default: "ENVVAR" to get our of env var rather than config): ' ,
168
- 'ENVVAR' ,
169
- )
170
-
171
- # Validate the Context Credentials
172
- validate_context_auth (pat , user_id , api_url )
173
-
174
- context = Context (
175
- name ,
176
- CLARIFAI_API_BASE = api_url ,
177
- CLARIFAI_USER_ID = user_id ,
178
- CLARIFAI_PAT = pat ,
179
- )
180
-
181
- if context .name == '' :
182
- context .name = 'default'
183
-
184
- ctx .obj .contexts [context .name ] = context
185
- ctx .obj .current_context = context .name
186
-
187
- ctx .obj .to_yaml ()
188
- logger .info (
189
- f"Login successful and Configuration saved successfully for context '{ context .name } '"
190
- )
191
-
192
-
193
- @cli .group (cls = AliasedGroup )
194
- def context ():
195
- """Manage contexts"""
196
-
197
-
198
- def pat_display (pat ):
199
- return pat [:5 ] + "****"
200
-
201
-
202
- def input_or_default (prompt , default ):
203
- value = input (prompt )
204
- return value if value else default
167
+ def current_context (ctx , output_format ):
168
+ """Show the current context's details."""
169
+ if output_format == 'name' :
170
+ print (ctx .obj .current_context )
171
+ elif output_format == 'json' :
172
+ print (json .dumps (ctx .obj .contexts [ctx .obj .current_context ].to_serializable_dict ()))
173
+ else :
174
+ print (yaml .safe_dump (ctx .obj .contexts [ctx .obj .current_context ].to_serializable_dict ()))
205
175
206
176
207
- @context .command ()
177
+ @config .command (aliases = [ 'create-context' , 'set-context' ] )
208
178
@click .argument ('name' )
209
179
@click .option ('--user-id' , required = False , help = 'User ID' )
210
180
@click .option ('--base-url' , required = False , help = 'Base URL' )
211
181
@click .option ('--pat' , required = False , help = 'Personal access token' )
212
182
@click .pass_context
213
- def create (
183
+ def create_context (
214
184
ctx ,
215
185
name ,
216
186
user_id = None ,
217
187
base_url = None ,
218
188
pat = None ,
219
189
):
220
- """Create a new context"""
190
+ """Create a new context. """
221
191
from clarifai .utils .cli import validate_context_auth
222
192
223
193
if name in ctx .obj .contexts :
@@ -234,22 +204,28 @@ def create(
234
204
'personal access token value (default: "ENVVAR" to get our of env var rather than config): ' ,
235
205
'ENVVAR' ,
236
206
)
237
-
238
- # Validate the Context Credentials
239
207
validate_context_auth (pat , user_id , base_url )
240
-
241
208
context = Context (name , CLARIFAI_USER_ID = user_id , CLARIFAI_API_BASE = base_url , CLARIFAI_PAT = pat )
242
209
ctx .obj .contexts [context .name ] = context
243
210
ctx .obj .to_yaml ()
244
211
logger .info (f"Context '{ name } ' created successfully" )
245
212
246
213
247
- # write a click command to delete a context
248
- @context .command (['rm' ])
214
+ @config .command (aliases = ['e' ])
215
+ @click .pass_context
216
+ def edit (
217
+ ctx ,
218
+ ):
219
+ """Open the configuration file for editing."""
220
+ # For now, just open the config file (not per-context)
221
+ os .system (f'{ os .environ .get ("EDITOR" , "vi" )} { ctx .obj .filename } ' )
222
+
223
+
224
+ @config .command (aliases = ['delete-context' ])
249
225
@click .argument ('name' )
250
226
@click .pass_context
251
- def delete (ctx , name ):
252
- """Delete a context"""
227
+ def delete_context (ctx , name ):
228
+ """Delete a context. """
253
229
if name not in ctx .obj .contexts :
254
230
print (f'{ name } is not a valid context' )
255
231
sys .exit (1 )
@@ -258,16 +234,29 @@ def delete(ctx, name):
258
234
print (f'{ name } deleted' )
259
235
260
236
261
- @context .command ()
262
- @click .argument ('name' , type = str )
237
+ @config .command (aliases = ['get-env' ])
263
238
@click .pass_context
264
- def use (ctx , name ):
265
- """Set the current context"""
266
- if name not in ctx .obj .contexts :
267
- raise click .UsageError ('Context not found' )
268
- ctx .obj .current_context = name
269
- ctx .obj .to_yaml ()
270
- print (f'Set { name } as the current context' )
239
+ def env (ctx ):
240
+ """Print env vars for the active context."""
241
+ ctx .obj .current .print_env_vars ()
242
+
243
+
244
+ @config .command (aliases = ['show' ])
245
+ @click .option ('-o' , '--output-format' , default = 'yaml' , type = click .Choice (['json' , 'yaml' ]))
246
+ @click .pass_context
247
+ def view (ctx , output_format ):
248
+ """Display the current configuration."""
249
+ config_dict = {
250
+ 'current-context' : ctx .obj .current_context ,
251
+ 'contexts' : {
252
+ name : context .to_serializable_dict () for name , context in ctx .obj .contexts .items ()
253
+ },
254
+ }
255
+
256
+ if output_format == 'json' :
257
+ print (json .dumps (config_dict , indent = 2 ))
258
+ else :
259
+ print (yaml .safe_dump (config_dict , default_flow_style = False ))
271
260
272
261
273
262
@cli .command ()
0 commit comments