outerbounds 0.3.68__py3-none-any.whl → 0.3.104__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. outerbounds/_vendor/PyYAML.LICENSE +20 -0
  2. outerbounds/_vendor/__init__.py +0 -0
  3. outerbounds/_vendor/_yaml/__init__.py +34 -0
  4. outerbounds/_vendor/click/__init__.py +73 -0
  5. outerbounds/_vendor/click/_compat.py +626 -0
  6. outerbounds/_vendor/click/_termui_impl.py +717 -0
  7. outerbounds/_vendor/click/_textwrap.py +49 -0
  8. outerbounds/_vendor/click/_winconsole.py +279 -0
  9. outerbounds/_vendor/click/core.py +2998 -0
  10. outerbounds/_vendor/click/decorators.py +497 -0
  11. outerbounds/_vendor/click/exceptions.py +287 -0
  12. outerbounds/_vendor/click/formatting.py +301 -0
  13. outerbounds/_vendor/click/globals.py +68 -0
  14. outerbounds/_vendor/click/parser.py +529 -0
  15. outerbounds/_vendor/click/py.typed +0 -0
  16. outerbounds/_vendor/click/shell_completion.py +580 -0
  17. outerbounds/_vendor/click/termui.py +787 -0
  18. outerbounds/_vendor/click/testing.py +479 -0
  19. outerbounds/_vendor/click/types.py +1073 -0
  20. outerbounds/_vendor/click/utils.py +580 -0
  21. outerbounds/_vendor/click.LICENSE +28 -0
  22. outerbounds/_vendor/vendor_any.txt +2 -0
  23. outerbounds/_vendor/yaml/__init__.py +471 -0
  24. outerbounds/_vendor/yaml/_yaml.cpython-311-darwin.so +0 -0
  25. outerbounds/_vendor/yaml/composer.py +146 -0
  26. outerbounds/_vendor/yaml/constructor.py +862 -0
  27. outerbounds/_vendor/yaml/cyaml.py +177 -0
  28. outerbounds/_vendor/yaml/dumper.py +138 -0
  29. outerbounds/_vendor/yaml/emitter.py +1239 -0
  30. outerbounds/_vendor/yaml/error.py +94 -0
  31. outerbounds/_vendor/yaml/events.py +104 -0
  32. outerbounds/_vendor/yaml/loader.py +62 -0
  33. outerbounds/_vendor/yaml/nodes.py +51 -0
  34. outerbounds/_vendor/yaml/parser.py +629 -0
  35. outerbounds/_vendor/yaml/reader.py +208 -0
  36. outerbounds/_vendor/yaml/representer.py +378 -0
  37. outerbounds/_vendor/yaml/resolver.py +245 -0
  38. outerbounds/_vendor/yaml/scanner.py +1555 -0
  39. outerbounds/_vendor/yaml/serializer.py +127 -0
  40. outerbounds/_vendor/yaml/tokens.py +129 -0
  41. outerbounds/command_groups/apps_cli.py +586 -0
  42. outerbounds/command_groups/cli.py +9 -5
  43. outerbounds/command_groups/local_setup_cli.py +1 -5
  44. outerbounds/command_groups/perimeters_cli.py +198 -25
  45. outerbounds/command_groups/tutorials_cli.py +111 -0
  46. outerbounds/command_groups/workstations_cli.py +2 -2
  47. outerbounds/utils/kubeconfig.py +2 -2
  48. outerbounds/utils/metaflowconfig.py +68 -9
  49. outerbounds/utils/schema.py +2 -2
  50. outerbounds/utils/utils.py +19 -0
  51. outerbounds/vendor.py +159 -0
  52. {outerbounds-0.3.68.dist-info → outerbounds-0.3.104.dist-info}/METADATA +14 -7
  53. outerbounds-0.3.104.dist-info/RECORD +59 -0
  54. {outerbounds-0.3.68.dist-info → outerbounds-0.3.104.dist-info}/WHEEL +1 -1
  55. outerbounds-0.3.68.dist-info/RECORD +0 -15
  56. {outerbounds-0.3.68.dist-info → outerbounds-0.3.104.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,586 @@
1
+ import json
2
+ import os
3
+ from os import path
4
+ from outerbounds._vendor import click
5
+ import requests
6
+
7
+ from ..utils import metaflowconfig
8
+ from ..utils.schema import (
9
+ CommandStatus,
10
+ OuterboundsCommandResponse,
11
+ OuterboundsCommandStatus,
12
+ )
13
+
14
+
15
+ @click.group()
16
+ def cli(**kwargs):
17
+ pass
18
+
19
+
20
+ @click.group(help="Manage apps")
21
+ def app(**kwargs):
22
+ pass
23
+
24
+
25
+ @app.command(help="Start an app using a port and a name")
26
+ @click.option(
27
+ "-d",
28
+ "--config-dir",
29
+ default=path.expanduser(os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")),
30
+ help="Path to Metaflow configuration directory",
31
+ show_default=True,
32
+ )
33
+ @click.option(
34
+ "-p",
35
+ "--profile",
36
+ default=os.environ.get("METAFLOW_PROFILE", ""),
37
+ help="The named metaflow profile in which your workstation exists",
38
+ )
39
+ @click.option(
40
+ "--port",
41
+ required=True,
42
+ help="Port number where you want to start your app",
43
+ type=int,
44
+ )
45
+ @click.option(
46
+ "--name",
47
+ required=True,
48
+ help="Name of your app",
49
+ type=str,
50
+ )
51
+ @click.option(
52
+ "-o",
53
+ "--output",
54
+ default="",
55
+ help="Show output in the specified format.",
56
+ type=click.Choice(["json", ""]),
57
+ )
58
+ def start(config_dir=None, profile=None, port=-1, name="", output=""):
59
+ if len(name) == 0 or len(name) >= 20:
60
+ click.secho(
61
+ "App name should not be more than 20 characters long.",
62
+ fg="red",
63
+ err=True,
64
+ )
65
+ return
66
+ elif not name.isalnum() or not name.islower():
67
+ click.secho(
68
+ "App name can only contain lowercase alphanumeric characters.",
69
+ fg="red",
70
+ err=True,
71
+ )
72
+ return
73
+
74
+ start_app_response = OuterboundsCommandResponse()
75
+
76
+ validate_workstation_step = CommandStatus(
77
+ "ValidateRunningOnWorkstation",
78
+ OuterboundsCommandStatus.OK,
79
+ "Command is being run on a workstation.",
80
+ )
81
+
82
+ list_workstations_step = CommandStatus(
83
+ "ListWorkstations",
84
+ OuterboundsCommandStatus.OK,
85
+ "List of workstations fetched.",
86
+ )
87
+
88
+ validate_request = CommandStatus(
89
+ "ValidateRequest",
90
+ OuterboundsCommandStatus.OK,
91
+ "Start app request is valid.",
92
+ )
93
+
94
+ start_app_step = CommandStatus(
95
+ "StartApp",
96
+ OuterboundsCommandStatus.OK,
97
+ f"App {name} started on port {port}!",
98
+ )
99
+
100
+ if "WORKSTATION_ID" not in os.environ:
101
+ validate_workstation_step.update(
102
+ OuterboundsCommandStatus.FAIL,
103
+ "All outerbounds app commands can only be run from a workstation.",
104
+ "",
105
+ )
106
+ start_app_response.add_step(validate_workstation_step)
107
+ click.secho(
108
+ "All outerbounds app commands can only be run from a workstation.",
109
+ fg="red",
110
+ err=True,
111
+ )
112
+
113
+ if output == "json":
114
+ click.echo(json.dumps(start_app_response.as_dict(), indent=4))
115
+ return
116
+
117
+ try:
118
+ try:
119
+ metaflow_token = metaflowconfig.get_metaflow_token_from_config(
120
+ config_dir, profile
121
+ )
122
+ api_url = metaflowconfig.get_sanitized_url_from_config(
123
+ config_dir, profile, "OBP_API_SERVER"
124
+ )
125
+
126
+ workstations_response = requests.get(
127
+ f"{api_url}/v1/workstations", headers={"x-api-key": metaflow_token}
128
+ )
129
+ workstations_response.raise_for_status()
130
+ start_app_response.add_step(list_workstations_step)
131
+ except:
132
+ click.secho("Failed to list workstations!", fg="red", err=True)
133
+ list_workstations_step.update(
134
+ OuterboundsCommandStatus.FAIL, "Failed to list workstations!", ""
135
+ )
136
+ start_app_response.add_step(list_workstations_step)
137
+ if output == "json":
138
+ click.echo(json.dumps(start_app_response.as_dict(), indent=4))
139
+ return
140
+
141
+ workstations_json = workstations_response.json()["workstations"]
142
+ for workstation in workstations_json:
143
+ if workstation["instance_id"] == os.environ["WORKSTATION_ID"]:
144
+ if "named_ports" in workstation["spec"]:
145
+ try:
146
+ ensure_app_start_request_is_valid(
147
+ workstation["spec"]["named_ports"], port, name
148
+ )
149
+ except ValueError as e:
150
+ click.secho(str(e), fg="red", err=True)
151
+ validate_request.update(
152
+ OuterboundsCommandStatus.FAIL,
153
+ str(e),
154
+ "",
155
+ )
156
+ start_app_response.add_step(validate_request)
157
+ if output == "json":
158
+ click.echo(
159
+ json.dumps(start_app_response.as_dict(), indent=4)
160
+ )
161
+ return
162
+
163
+ start_app_response.add_step(validate_request)
164
+
165
+ for named_port in workstation["spec"]["named_ports"]:
166
+ if int(named_port["port"]) == port:
167
+ if named_port["enabled"] and named_port["name"] == name:
168
+ click.secho(
169
+ f"App {name} already running on port {port}!",
170
+ fg="green",
171
+ err=True,
172
+ )
173
+ click.secho(
174
+ f"App URL: {api_url.replace('api', 'ui')}/apps/{os.environ['WORKSTATION_ID']}/{name}/",
175
+ fg="green",
176
+ err=True,
177
+ )
178
+ start_app_response.add_step(start_app_step)
179
+ if output == "json":
180
+ click.echo(
181
+ json.dumps(
182
+ start_app_response.as_dict(), indent=4
183
+ )
184
+ )
185
+ return
186
+ else:
187
+ try:
188
+ response = requests.put(
189
+ f"{api_url}/v1/workstations/update/{os.environ['WORKSTATION_ID']}/namedports",
190
+ headers={"x-api-key": metaflow_token},
191
+ json={
192
+ "port": port,
193
+ "name": name,
194
+ "enabled": True,
195
+ },
196
+ )
197
+
198
+ response.raise_for_status()
199
+ click.secho(
200
+ f"App {name} started on port {port}!",
201
+ fg="green",
202
+ err=True,
203
+ )
204
+ click.secho(
205
+ f"App URL: {api_url.replace('api', 'ui')}/apps/{os.environ['WORKSTATION_ID']}/{name}/",
206
+ fg="green",
207
+ err=True,
208
+ )
209
+ except Exception:
210
+ click.secho(
211
+ f"Failed to start app {name} on port {port}!",
212
+ fg="red",
213
+ err=True,
214
+ )
215
+ start_app_step.update(
216
+ OuterboundsCommandStatus.FAIL,
217
+ f"Failed to start app {name} on port {port}!",
218
+ "",
219
+ )
220
+
221
+ start_app_response.add_step(start_app_step)
222
+ if output == "json":
223
+ click.echo(
224
+ json.dumps(
225
+ start_app_response.as_dict(), indent=4
226
+ )
227
+ )
228
+ return
229
+ except Exception as e:
230
+ click.secho(f"Failed to start app {name} on port {port}!", fg="red", err=True)
231
+ start_app_step.update(
232
+ OuterboundsCommandStatus.FAIL,
233
+ f"Failed to start app {name} on port {port}!",
234
+ "",
235
+ )
236
+ start_app_response.add_step(start_app_step)
237
+ if output == "json":
238
+ click.secho(json.dumps(start_app_response.as_dict(), indent=4))
239
+
240
+
241
+ @app.command(help="Stop an app using its port number")
242
+ @click.option(
243
+ "-d",
244
+ "--config-dir",
245
+ default=path.expanduser(os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")),
246
+ help="Path to Metaflow configuration directory",
247
+ show_default=True,
248
+ )
249
+ @click.option(
250
+ "-p",
251
+ "--profile",
252
+ default=os.environ.get("METAFLOW_PROFILE", ""),
253
+ help="The named metaflow profile in which your workstation exists",
254
+ )
255
+ @click.option(
256
+ "--port",
257
+ required=False,
258
+ default=-1,
259
+ help="Port number where you want to start your app.",
260
+ type=int,
261
+ )
262
+ @click.option(
263
+ "--name",
264
+ required=False,
265
+ help="Name of your app",
266
+ default="",
267
+ type=str,
268
+ )
269
+ @click.option(
270
+ "-o",
271
+ "--output",
272
+ default="",
273
+ help="Show output in the specified format.",
274
+ type=click.Choice(["json", ""]),
275
+ )
276
+ def stop(config_dir=None, profile=None, port=-1, name="", output=""):
277
+ if port == -1 and not name:
278
+ click.secho(
279
+ "Please provide either a port number or a name to stop the app.",
280
+ fg="red",
281
+ err=True,
282
+ )
283
+ return
284
+ elif port > 0 and name:
285
+ click.secho(
286
+ "Please provide either a port number or a name to stop the app, not both.",
287
+ fg="red",
288
+ err=True,
289
+ )
290
+ return
291
+
292
+ stop_app_response = OuterboundsCommandResponse()
293
+
294
+ validate_workstation_step = CommandStatus(
295
+ "ValidateRunningOnWorkstation",
296
+ OuterboundsCommandStatus.OK,
297
+ "Command is being run on a workstation.",
298
+ )
299
+
300
+ list_workstations_step = CommandStatus(
301
+ "ListWorkstations",
302
+ OuterboundsCommandStatus.OK,
303
+ "List of workstations fetched.",
304
+ )
305
+
306
+ validate_port_exists = CommandStatus(
307
+ "ValidatePortExists",
308
+ OuterboundsCommandStatus.OK,
309
+ "Port exists on workstation",
310
+ )
311
+
312
+ stop_app_step = CommandStatus(
313
+ "StopApp",
314
+ OuterboundsCommandStatus.OK,
315
+ f"App stopped on port {port}!",
316
+ )
317
+
318
+ if "WORKSTATION_ID" not in os.environ:
319
+ validate_workstation_step.update(
320
+ OuterboundsCommandStatus.FAIL,
321
+ "All outerbounds app commands can only be run from a workstation.",
322
+ "",
323
+ )
324
+ stop_app_response.add_step(validate_workstation_step)
325
+ click.secho(
326
+ "All outerbounds app commands can only be run from a workstation.",
327
+ fg="red",
328
+ err=True,
329
+ )
330
+
331
+ if output == "json":
332
+ click.echo(json.dumps(stop_app_response.as_dict(), indent=4))
333
+ return
334
+
335
+ try:
336
+ try:
337
+ metaflow_token = metaflowconfig.get_metaflow_token_from_config(
338
+ config_dir, profile
339
+ )
340
+ api_url = metaflowconfig.get_sanitized_url_from_config(
341
+ config_dir, profile, "OBP_API_SERVER"
342
+ )
343
+
344
+ workstations_response = requests.get(
345
+ f"{api_url}/v1/workstations", headers={"x-api-key": metaflow_token}
346
+ )
347
+ workstations_response.raise_for_status()
348
+ stop_app_response.add_step(list_workstations_step)
349
+ except:
350
+ click.secho("Failed to list workstations!", fg="red", err=True)
351
+ list_workstations_step.update(
352
+ OuterboundsCommandStatus.FAIL, "Failed to list workstations!", ""
353
+ )
354
+ stop_app_response.add_step(list_workstations_step)
355
+ if output == "json":
356
+ click.echo(json.dumps(stop_app_response.as_dict(), indent=4))
357
+ return
358
+
359
+ app_found = False
360
+ workstations_json = workstations_response.json()["workstations"]
361
+ for workstation in workstations_json:
362
+ if workstation["instance_id"] == os.environ["WORKSTATION_ID"]:
363
+ if "named_ports" in workstation["spec"]:
364
+ for named_port in workstation["spec"]["named_ports"]:
365
+ if (
366
+ int(named_port["port"]) == port
367
+ or named_port["name"] == name
368
+ ):
369
+ app_found = True
370
+ stop_app_response.add_step(validate_port_exists)
371
+ if named_port["enabled"]:
372
+ try:
373
+ response = requests.put(
374
+ f"{api_url}/v1/workstations/update/{os.environ['WORKSTATION_ID']}/namedports",
375
+ headers={"x-api-key": metaflow_token},
376
+ json={
377
+ "port": named_port["port"],
378
+ "name": named_port["name"],
379
+ "enabled": False,
380
+ },
381
+ )
382
+ response.raise_for_status()
383
+ click.secho(
384
+ f"App {named_port['name']} stopped on port {named_port['port']}!",
385
+ fg="green",
386
+ err=True,
387
+ )
388
+ except Exception as e:
389
+ click.secho(
390
+ f"Failed to stop app {named_port['name']} on port {named_port['port']}!",
391
+ fg="red",
392
+ err=True,
393
+ )
394
+ stop_app_step.update(
395
+ OuterboundsCommandStatus.FAIL,
396
+ f"Failed to stop app {named_port['name']} on port {named_port['port']}!",
397
+ "",
398
+ )
399
+
400
+ stop_app_response.add_step(stop_app_step)
401
+ if output == "json":
402
+ click.echo(
403
+ json.dumps(
404
+ stop_app_response.as_dict(), indent=4
405
+ )
406
+ )
407
+ return
408
+
409
+ if app_found:
410
+ already_stopped_message = (
411
+ f"No deployed app named {name} found."
412
+ if name
413
+ else f"There is no app deployed on port {port}"
414
+ )
415
+ click.secho(
416
+ already_stopped_message,
417
+ fg="green",
418
+ err=True,
419
+ )
420
+ stop_app_response.add_step(stop_app_step)
421
+ if output == "json":
422
+ click.echo(json.dumps(stop_app_response.as_dict(), indent=4))
423
+ return
424
+
425
+ err_message = (
426
+ (f"Port {port} not found on workstation {os.environ['WORKSTATION_ID']}")
427
+ if port != -1
428
+ else f"App {name} not found on workstation {os.environ['WORKSTATION_ID']}"
429
+ )
430
+
431
+ click.secho(
432
+ err_message,
433
+ fg="red",
434
+ err=True,
435
+ )
436
+
437
+ validate_port_exists.update(
438
+ OuterboundsCommandStatus.FAIL,
439
+ err_message,
440
+ "",
441
+ )
442
+ stop_app_response.add_step(validate_port_exists)
443
+ if output == "json":
444
+ click.echo(json.dumps(stop_app_response.as_dict(), indent=4))
445
+ except Exception as e:
446
+ click.secho(f"Failed to stop app on port {port}!", fg="red", err=True)
447
+ stop_app_step.update(
448
+ OuterboundsCommandStatus.FAIL, f"Failed to stop on port {port}!", ""
449
+ )
450
+ stop_app_response.add_step(stop_app_step)
451
+ if output == "json":
452
+ click.echo(json.dumps(stop_app_response.as_dict(), indent=4))
453
+
454
+
455
+ @app.command(help="Stop an app using its port number")
456
+ @click.option(
457
+ "-d",
458
+ "--config-dir",
459
+ default=path.expanduser(os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")),
460
+ help="Path to Metaflow configuration directory",
461
+ show_default=True,
462
+ )
463
+ @click.option(
464
+ "-p",
465
+ "--profile",
466
+ default=os.environ.get("METAFLOW_PROFILE", ""),
467
+ help="The named metaflow profile in which your workstation exists",
468
+ )
469
+ @click.option(
470
+ "-o",
471
+ "--output",
472
+ default="",
473
+ help="Show output in the specified format.",
474
+ type=click.Choice(["json", ""]),
475
+ )
476
+ def list(config_dir=None, profile=None, output=""):
477
+ list_app_response = OuterboundsCommandResponse()
478
+
479
+ validate_workstation_step = CommandStatus(
480
+ "ValidateRunningOnWorkstation",
481
+ OuterboundsCommandStatus.OK,
482
+ "Command is being run on a workstation.",
483
+ )
484
+
485
+ list_workstations_step = CommandStatus(
486
+ "ListWorkstations",
487
+ OuterboundsCommandStatus.OK,
488
+ "List of workstations fetched.",
489
+ )
490
+
491
+ if "WORKSTATION_ID" not in os.environ:
492
+ validate_workstation_step.update(
493
+ OuterboundsCommandStatus.FAIL,
494
+ "All outerbounds app commands can only be run from a workstation.",
495
+ "",
496
+ )
497
+ list_app_response.add_step(validate_workstation_step)
498
+ click.secho(
499
+ "All outerbounds app commands can only be run from a workstation.",
500
+ fg="red",
501
+ err=True,
502
+ )
503
+
504
+ if output == "json":
505
+ click.echo(json.dumps(list_app_response.as_dict(), indent=4))
506
+ return
507
+
508
+ try:
509
+ try:
510
+ metaflow_token = metaflowconfig.get_metaflow_token_from_config(
511
+ config_dir, profile
512
+ )
513
+ api_url = metaflowconfig.get_sanitized_url_from_config(
514
+ config_dir, profile, "OBP_API_SERVER"
515
+ )
516
+
517
+ workstations_response = requests.get(
518
+ f"{api_url}/v1/workstations", headers={"x-api-key": metaflow_token}
519
+ )
520
+ workstations_response.raise_for_status()
521
+ list_app_response.add_step(list_workstations_step)
522
+ except:
523
+ click.secho("Failed to list workstations!", fg="red", err=True)
524
+ list_workstations_step.update(
525
+ OuterboundsCommandStatus.FAIL, "Failed to list workstations!", ""
526
+ )
527
+ list_app_response.add_step(list_workstations_step)
528
+ if output == "json":
529
+ click.echo(json.dumps(list_app_response.as_dict(), indent=4))
530
+ return
531
+
532
+ workstations_json = workstations_response.json()["workstations"]
533
+ for workstation in workstations_json:
534
+ if workstation["instance_id"] == os.environ["WORKSTATION_ID"]:
535
+ if "named_ports" in workstation["spec"]:
536
+ for named_port in workstation["spec"]["named_ports"]:
537
+ if named_port["enabled"]:
538
+ click.secho(
539
+ f"App Name: {named_port['name']}", fg="green", err=True
540
+ )
541
+ click.secho(
542
+ f"App Port on Workstation: {named_port['port']}",
543
+ fg="green",
544
+ err=True,
545
+ )
546
+ click.secho(f"App Status: Deployed", fg="green", err=True)
547
+ click.secho(
548
+ f"App URL: {api_url.replace('api', 'ui')}/apps/{os.environ['WORKSTATION_ID']}/{named_port['name']}/",
549
+ fg="green",
550
+ err=True,
551
+ )
552
+ else:
553
+ click.secho(
554
+ f"App Port on Workstation: {named_port['port']}",
555
+ fg="yellow",
556
+ err=True,
557
+ )
558
+ click.secho(
559
+ f"App Status: Not Deployed", fg="yellow", err=True
560
+ )
561
+
562
+ click.echo("\n", err=True)
563
+ except Exception as e:
564
+ click.secho(f"Failed to list apps!", fg="red", err=True)
565
+ if output == "json":
566
+ click.echo(json.dumps(list_app_response.as_dict(), indent=4))
567
+
568
+
569
+ def ensure_app_start_request_is_valid(existing_named_ports, port: int, name: str):
570
+ existing_apps_by_port = {np["port"]: np for np in existing_named_ports}
571
+
572
+ if port not in existing_apps_by_port:
573
+ raise ValueError(f"Port {port} not found on workstation")
574
+
575
+ for existing_named_port in existing_named_ports:
576
+ if (
577
+ name == existing_named_port["name"]
578
+ and existing_named_port["port"] != port
579
+ and existing_named_port["enabled"]
580
+ ):
581
+ raise ValueError(
582
+ f"App with name '{name}' is already deployed on port {existing_named_port['port']}"
583
+ )
584
+
585
+
586
+ cli.add_command(app, name="app")
@@ -1,12 +1,16 @@
1
- import click
2
- from . import local_setup_cli
3
- from . import workstations_cli
4
- from . import perimeters_cli
1
+ from outerbounds._vendor import click
2
+ from . import local_setup_cli, workstations_cli, perimeters_cli, apps_cli, tutorials_cli
5
3
 
6
4
 
7
5
  @click.command(
8
6
  cls=click.CommandCollection,
9
- sources=[local_setup_cli.cli, workstations_cli.cli, perimeters_cli.cli],
7
+ sources=[
8
+ local_setup_cli.cli,
9
+ workstations_cli.cli,
10
+ perimeters_cli.cli,
11
+ apps_cli.cli,
12
+ tutorials_cli.cli,
13
+ ],
10
14
  )
11
15
  def cli(**kwargs):
12
16
  pass
@@ -11,8 +11,7 @@ from importlib.machinery import PathFinder
11
11
  from os import path
12
12
  from pathlib import Path
13
13
  from typing import Any, Callable, Dict, List
14
-
15
- import click
14
+ from outerbounds._vendor import click
16
15
  import requests
17
16
  from requests.exceptions import HTTPError
18
17
 
@@ -641,7 +640,6 @@ class ConfigurationWriter:
641
640
  if config_type == "inline":
642
641
  if "OBP_PERIMETER" in self.decoded_config:
643
642
  self.selected_perimeter = self.decoded_config["OBP_PERIMETER"]
644
-
645
643
  if "OBP_METAFLOW_CONFIG_URL" in self.decoded_config:
646
644
  self.decoded_config = {
647
645
  "OBP_METAFLOW_CONFIG_URL": self.decoded_config[
@@ -702,8 +700,6 @@ class ConfigurationWriter:
702
700
  with open(config_path, "w") as fd:
703
701
  json.dump(self.existing, fd, indent=4)
704
702
 
705
- # Every time a config is initialized, we should also reset the corresponding ob_config[_profile].json
706
- remote_config = metaflowconfig.init_config(self.out_dir, self.profile)
707
703
  if self.selected_perimeter and "OBP_METAFLOW_CONFIG_URL" in self.decoded_config:
708
704
  with open(self.ob_config_path, "w") as fd:
709
705
  ob_config_dict = {