outerbounds 0.3.151__py3-none-any.whl → 0.3.152__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.
@@ -4,6 +4,8 @@ from outerbounds._vendor import click
4
4
  import requests
5
5
  import time
6
6
  import random
7
+ import shutil
8
+ import subprocess
7
9
 
8
10
  from ..utils import metaflowconfig
9
11
 
@@ -113,7 +115,12 @@ def start(config_dir=None, profile=None, port=-1, name=""):
113
115
  err=True,
114
116
  )
115
117
  click.secho(
116
- f"App URL: {api_url.replace('api', 'ui')}/apps/{workstation_id}/{name}/",
118
+ f"Browser URL: {api_url.replace('api', 'ui')}/apps/{workstation_id}/{name}/",
119
+ fg="green",
120
+ err=True,
121
+ )
122
+ click.secho(
123
+ f"App URL: {api_url}/apps/{workstation_id}/{name}/",
117
124
  fg="green",
118
125
  err=True,
119
126
  )
@@ -145,7 +152,12 @@ def start(config_dir=None, profile=None, port=-1, name=""):
145
152
  err=True,
146
153
  )
147
154
  click.secho(
148
- f"App URL: {api_url.replace('api', 'ui')}/apps/{os.environ['WORKSTATION_ID']}/{name}/",
155
+ f"Browser URL: {api_url.replace('api', 'ui')}/apps/{os.environ['WORKSTATION_ID']}/{name}/",
156
+ fg="green",
157
+ err=True,
158
+ )
159
+ click.secho(
160
+ f"App URL: {api_url}/apps/{os.environ['WORKSTATION_ID']}/{name}/",
149
161
  fg="green",
150
162
  err=True,
151
163
  )
@@ -301,6 +313,93 @@ def stop(config_dir=None, profile=None, port=-1, name=""):
301
313
  click.secho(f"Failed to stop app on port {port}!", fg="red", err=True)
302
314
 
303
315
 
316
+ @app.command(help="Kill the process associated with an app.")
317
+ @click.option(
318
+ "-d",
319
+ "--config-dir",
320
+ default=path.expanduser(os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")),
321
+ help="Path to Metaflow configuration directory",
322
+ show_default=True,
323
+ )
324
+ @click.option(
325
+ "-p",
326
+ "--profile",
327
+ default=os.environ.get("METAFLOW_PROFILE", ""),
328
+ help="The named metaflow profile in which your workstation exists",
329
+ )
330
+ @click.option(
331
+ "--name",
332
+ required=False,
333
+ help="Name of your app",
334
+ default="",
335
+ type=str,
336
+ )
337
+ def kill_process(config_dir=None, profile=None, port=-1, name=""):
338
+ if port > 0 and name:
339
+ click.secho(
340
+ "Please provide either a port number or a name to stop the app, not both.",
341
+ fg="red",
342
+ err=True,
343
+ )
344
+ return
345
+
346
+ if "WORKSTATION_ID" not in os.environ:
347
+ click.secho(
348
+ "All outerbounds app commands can only be run from a workstation.",
349
+ fg="red",
350
+ err=True,
351
+ )
352
+
353
+ return
354
+
355
+ supervisorctl_exists = shutil.which("supervisorctl")
356
+ if not supervisorctl_exists:
357
+ click.secho(
358
+ "This workstation does not support automated app deployment and management. Pleasr reach out to outerbounds support!",
359
+ fg="red",
360
+ err=True,
361
+ )
362
+ return
363
+
364
+ supervisorctl_command = ["supervisorctl", "stop", name]
365
+
366
+ # This is somewhat ugly way of doing this, but there aren't any better ways.
367
+ # Since we use supervisorctl to manage our apps, we have to rely on external calls to
368
+ # kill the process.
369
+ result = subprocess.run(supervisorctl_command, capture_output=True, text=True)
370
+ if result.returncode == 0:
371
+ # It gets uglier.
372
+ # When the process is not running, which is likely due to a user error, the output looks like:
373
+ # myapp: ERROR (not running)
374
+ # but the return code is still 0.
375
+ # If the stop is successful, the output looks like:
376
+ # myapp: stopped
377
+
378
+ if result.stdout.startswith(f"{name}: ERROR (not running)"):
379
+ click.secho(
380
+ f"Process {name} is not in a running state to kill!",
381
+ fg="yellow",
382
+ err=True,
383
+ )
384
+ return
385
+ elif result.stdout.startswith(f"{name}: stopped"):
386
+ click.secho(f"Process {name} killed successfully!", fg="green", err=True)
387
+ return
388
+ else:
389
+ click.secho(f"Process {name} stopped!", fg="red", err=True)
390
+ return
391
+ elif result.returncode == 1:
392
+ # One of the cases where this can happen is if the app name itself is wrong.
393
+ # In this case, the output looks like:
394
+ # 'mya111pp: ERROR (no such process)\n'
395
+ if result.stdout.startswith(f"{name}: ERROR (no such process)"):
396
+ click.secho(f"Process {name} does not exist!", fg="red", err=True)
397
+ return
398
+ else:
399
+ click.secho(f"Failed to kill process {name}!", fg="red", err=True)
400
+ return
401
+
402
+
304
403
  @app.command(help="List all apps on the workstation")
305
404
  @click.option(
306
405
  "-d",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: outerbounds
3
- Version: 0.3.151
3
+ Version: 0.3.152
4
4
  Summary: More Data Science, Less Administration
5
5
  License: Proprietary
6
6
  Keywords: data science,machine learning,MLOps
@@ -27,9 +27,9 @@ Requires-Dist: google-auth (>=2.27.0,<3.0.0) ; extra == "gcp"
27
27
  Requires-Dist: google-cloud-secret-manager (>=2.20.0,<3.0.0) ; extra == "gcp"
28
28
  Requires-Dist: google-cloud-storage (>=2.14.0,<3.0.0) ; extra == "gcp"
29
29
  Requires-Dist: metaflow-checkpoint (==0.1.9)
30
- Requires-Dist: ob-metaflow (==2.15.6.1)
31
- Requires-Dist: ob-metaflow-extensions (==1.1.138)
32
- Requires-Dist: ob-metaflow-stubs (==6.0.3.151)
30
+ Requires-Dist: ob-metaflow (==2.15.7.1)
31
+ Requires-Dist: ob-metaflow-extensions (==1.1.140)
32
+ Requires-Dist: ob-metaflow-stubs (==6.0.3.152)
33
33
  Requires-Dist: opentelemetry-distro (==0.41b0)
34
34
  Requires-Dist: opentelemetry-exporter-otlp-proto-http (==1.20.0)
35
35
  Requires-Dist: opentelemetry-instrumentation-requests (==0.41b0)
@@ -41,7 +41,7 @@ outerbounds/_vendor/yaml/serializer.py,sha256=8wFZRy9SsQSktF_f9OOroroqsh4qVUe53r
41
41
  outerbounds/_vendor/yaml/tokens.py,sha256=JBSu38wihGr4l73JwbfMA7Ks1-X84g8-NskTz7KwPmA,2578
42
42
  outerbounds/cli_main.py,sha256=e9UMnPysmc7gbrimq2I4KfltggyU7pw59Cn9aEguVcU,74
43
43
  outerbounds/command_groups/__init__.py,sha256=QPWtj5wDRTINDxVUL7XPqG3HoxHNvYOg08EnuSZB2Hc,21
44
- outerbounds/command_groups/apps_cli.py,sha256=8jmQufa0bK2sfRfs7DiWjoJ1oWiqZAixsL4Dte_KY4Y,17201
44
+ outerbounds/command_groups/apps_cli.py,sha256=v9OlQ1b4BGB-cBZiHB6W5gDocDoMmrQ7zdK11QiJ-B8,20847
45
45
  outerbounds/command_groups/cli.py,sha256=YsDS-AKhhwwSH65mgNsmjeg1U2bk202V5NpIYnXEdb8,440
46
46
  outerbounds/command_groups/fast_bakery_cli.py,sha256=5kja7v6C651XAY6dsP_IkBPJQgfU4hA4S9yTOiVPhW0,6213
47
47
  outerbounds/command_groups/local_setup_cli.py,sha256=tuuqJRXQ_guEwOuQSIf9wkUU0yg8yAs31myGViAK15s,36364
@@ -54,7 +54,7 @@ outerbounds/utils/metaflowconfig.py,sha256=l2vJbgPkLISU-XPGZFaC8ZKmYFyJemlD6bwB-
54
54
  outerbounds/utils/schema.py,sha256=lMUr9kNgn9wy-sO_t_Tlxmbt63yLeN4b0xQXbDUDj4A,2331
55
55
  outerbounds/utils/utils.py,sha256=4Z8cszNob_8kDYCLNTrP-wWads_S_MdL3Uj3ju4mEsk,501
56
56
  outerbounds/vendor.py,sha256=gRLRJNXtZBeUpPEog0LOeIsl6GosaFFbCxUvR4bW6IQ,5093
57
- outerbounds-0.3.151.dist-info/METADATA,sha256=HJd3SOqWMsX2oJ28gzynFOj-0QSTSeVDR076OpX9HfY,1761
58
- outerbounds-0.3.151.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
59
- outerbounds-0.3.151.dist-info/entry_points.txt,sha256=7ye0281PKlvqxu15rjw60zKg2pMsXI49_A8BmGqIqBw,47
60
- outerbounds-0.3.151.dist-info/RECORD,,
57
+ outerbounds-0.3.152.dist-info/METADATA,sha256=fNqe7vT9wc3QsEGzA5HiOYvCqTtBvu2BNgPjfAyABEA,1761
58
+ outerbounds-0.3.152.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
59
+ outerbounds-0.3.152.dist-info/entry_points.txt,sha256=7ye0281PKlvqxu15rjw60zKg2pMsXI49_A8BmGqIqBw,47
60
+ outerbounds-0.3.152.dist-info/RECORD,,