outerbounds 0.3.187__py3-none-any.whl → 0.3.188rc0__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.
outerbounds/__init__.py CHANGED
@@ -1 +1,3 @@
1
- from .command_groups import cli
1
+ from . import apps
2
+
3
+ __all__ = ["apps"]
@@ -0,0 +1,28 @@
1
+ from outerbounds._vendor import click
2
+ import os
3
+
4
+ OUTERBOUNDS_APP_CLI_AVAILABLE = True
5
+ os.environ["APPS_CLI_LOADING_IN_OUTERBOUNDS"] = "true"
6
+ try:
7
+ from metaflow.ob_internal import app_core # type: ignore
8
+ except ImportError:
9
+ OUTERBOUNDS_APP_CLI_AVAILABLE = False
10
+
11
+
12
+ if not OUTERBOUNDS_APP_CLI_AVAILABLE:
13
+
14
+ @click.group()
15
+ def _cli():
16
+ pass
17
+
18
+ @_cli.group(help="Dummy Group to append to CLI for Safety")
19
+ def app():
20
+ pass
21
+
22
+ @app.command(help="Dummy Command to append to CLI for Safety")
23
+ def cannot_deploy():
24
+ raise Exception("Outerbounds App CLI not available")
25
+
26
+ app_cli_group = app
27
+ else:
28
+ app_cli_group = app_core.app_cli.app
@@ -8,6 +8,7 @@ import shutil
8
8
  import subprocess
9
9
 
10
10
  from ..utils import metaflowconfig
11
+ from ..apps import app_cli_group as app
11
12
 
12
13
  APP_READY_POLL_TIMEOUT_SECONDS = 300
13
14
  # Even after our backend validates that the app routes are ready, it takes a few seconds for
@@ -20,11 +21,6 @@ def cli(**kwargs):
20
21
  pass
21
22
 
22
23
 
23
- @click.group(help="Manage apps")
24
- def app(**kwargs):
25
- pass
26
-
27
-
28
24
  @app.command(help="Start an app using a port and a name")
29
25
  @click.option(
30
26
  "-d",
@@ -414,7 +410,7 @@ def kill_process(config_dir=None, profile=None, port=-1, name=""):
414
410
  default=os.environ.get("METAFLOW_PROFILE", ""),
415
411
  help="The named metaflow profile in which your workstation exists",
416
412
  )
417
- def list(config_dir=None, profile=None):
413
+ def list_local(config_dir=None, profile=None):
418
414
  if "WORKSTATION_ID" not in os.environ:
419
415
  click.secho(
420
416
  "All outerbounds app commands can only be run from a workstation.",
@@ -8,6 +8,7 @@ from . import (
8
8
  fast_bakery_cli,
9
9
  secrets_cli,
10
10
  kubernetes_cli,
11
+ flowprojects_cli,
11
12
  )
12
13
 
13
14
 
@@ -22,6 +23,7 @@ from . import (
22
23
  fast_bakery_cli.cli,
23
24
  secrets_cli.cli,
24
25
  kubernetes_cli.cli,
26
+ flowprojects_cli.cli,
25
27
  ],
26
28
  )
27
29
  def cli(**kwargs):
@@ -0,0 +1,137 @@
1
+ import json
2
+ import os
3
+ import sys
4
+ import requests
5
+
6
+ from ..utils import metaflowconfig
7
+ from outerbounds._vendor import click
8
+
9
+
10
+ @click.group()
11
+ def cli(**kwargs):
12
+ pass
13
+
14
+
15
+ @cli.group(help="Commands for pushing Deployments metadata.", hidden=True)
16
+ def flowproject(**kwargs):
17
+ pass
18
+
19
+
20
+ @flowproject.command()
21
+ @click.option(
22
+ "-d",
23
+ "--config-dir",
24
+ default=os.path.expanduser(os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")),
25
+ help="Path to Metaflow configuration directory",
26
+ show_default=True,
27
+ )
28
+ @click.option(
29
+ "-p",
30
+ "--profile",
31
+ default=os.environ.get("METAFLOW_PROFILE", ""),
32
+ help="The named metaflow profile in which your workstation exists",
33
+ )
34
+ @click.option("--id", help="The ID for this deployment")
35
+ def get_metadata(config_dir, profile, id):
36
+ api_url = metaflowconfig.get_sanitized_url_from_config(
37
+ config_dir, profile, "OBP_API_SERVER"
38
+ )
39
+ perimeter = _get_perimeter()
40
+ headers = _get_request_headers()
41
+
42
+ project, branch = _parse_id(id)
43
+
44
+ # GET the latest flowproject config in order to modify it
45
+ # /v1/perimeters/:perimeter/:project/:branch/flowprojects/latest
46
+ response = requests.get(
47
+ url=f"{api_url}/v1/perimeters/{perimeter}/projects/{project}/branches/{branch}/latestflowproject",
48
+ headers=headers,
49
+ )
50
+ if response.status_code >= 500:
51
+ raise Exception("API request failed.")
52
+
53
+ body = response.json()
54
+ if response.status_code >= 400:
55
+ raise Exception("request failed: %s" % body)
56
+
57
+ out = json.dumps(body)
58
+
59
+ print(out, file=sys.stdout)
60
+
61
+
62
+ @flowproject.command()
63
+ @click.option(
64
+ "-d",
65
+ "--config-dir",
66
+ default=os.path.expanduser(os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")),
67
+ help="Path to Metaflow configuration directory",
68
+ show_default=True,
69
+ )
70
+ @click.option(
71
+ "-p",
72
+ "--profile",
73
+ default=os.environ.get("METAFLOW_PROFILE", ""),
74
+ help="The named metaflow profile in which your workstation exists",
75
+ )
76
+ @click.argument("json_str")
77
+ def set_metadata(config_dir, profile, json_str):
78
+ api_url = metaflowconfig.get_sanitized_url_from_config(
79
+ config_dir, profile, "OBP_API_SERVER"
80
+ )
81
+
82
+ perimeter = _get_perimeter()
83
+ headers = _get_request_headers()
84
+ payload = json.loads(json_str)
85
+
86
+ # POST the updated flowproject config
87
+ # /v1/perimeters/:perimeter/flowprojects
88
+ response = requests.post(
89
+ url=f"{api_url}/v1/perimeters/{perimeter}/flowprojects",
90
+ json=payload,
91
+ headers=headers,
92
+ )
93
+ if response.status_code >= 500:
94
+ raise Exception("API request failed. %s" % response.text)
95
+
96
+ if response.status_code >= 400:
97
+ raise Exception("request failed: %s" % response.text)
98
+ body = response.json()
99
+
100
+ print(body, file=sys.stdout)
101
+
102
+
103
+ def _get_request_headers():
104
+ headers = {"Content-Type": "application/json", "Connection": "keep-alive"}
105
+ try:
106
+ from metaflow.metaflow_config import SERVICE_HEADERS
107
+
108
+ headers = {**headers, **(SERVICE_HEADERS or {})}
109
+ except ImportError:
110
+ headers = headers
111
+
112
+ return headers
113
+
114
+
115
+ def _get_perimeter():
116
+ # Get current perimeter
117
+ from metaflow_extensions.outerbounds.remote_config import init_config # type: ignore
118
+
119
+ conf = init_config()
120
+ if "OBP_PERIMETER" in conf:
121
+ perimeter = conf["OBP_PERIMETER"]
122
+ else:
123
+ # if the perimeter is not in metaflow config, try to get it from the environment
124
+ perimeter = os.environ.get("OBP_PERIMETER", None)
125
+ if perimeter is None:
126
+ raise Exception("Perimeter not found in config, but is required.")
127
+
128
+ return perimeter
129
+
130
+
131
+ def _parse_id(id: str):
132
+ parts = id.split("/")
133
+ if len(parts) != 2:
134
+ raise Exception("ID should consist of two parts: project/branch")
135
+
136
+ project, branch = parts
137
+ return project, branch
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: outerbounds
3
- Version: 0.3.187
3
+ Version: 0.3.188rc0
4
4
  Summary: More Data Science, Less Administration
5
5
  License: Proprietary
6
6
  Keywords: data science,machine learning,MLOps
@@ -29,8 +29,8 @@ Requires-Dist: google-cloud-secret-manager (>=2.20.0,<3.0.0) ; extra == "gcp"
29
29
  Requires-Dist: google-cloud-storage (>=2.14.0,<3.0.0) ; extra == "gcp"
30
30
  Requires-Dist: metaflow_checkpoint (==0.2.4)
31
31
  Requires-Dist: ob-metaflow (==2.15.18.1)
32
- Requires-Dist: ob-metaflow-extensions (==1.1.174)
33
- Requires-Dist: ob-metaflow-stubs (==6.0.3.187)
32
+ Requires-Dist: ob-metaflow-extensions (==1.1.175rc0)
33
+ Requires-Dist: ob-metaflow-stubs (==6.0.3.188rc0)
34
34
  Requires-Dist: opentelemetry-distro (>=0.41b0) ; extra == "otel"
35
35
  Requires-Dist: opentelemetry-exporter-otlp-proto-http (>=1.20.0) ; extra == "otel"
36
36
  Requires-Dist: opentelemetry-instrumentation-requests (>=0.41b0) ; extra == "otel"
@@ -1,4 +1,4 @@
1
- outerbounds/__init__.py,sha256=GPdaubvAYF8pOFWJ3b-sPMKCpyfpteWVMZWkmaYhxRw,32
1
+ outerbounds/__init__.py,sha256=8kikk4NZ0M0ymHuZN2mzw4LpJKFk0rvjYZ1uRefM7PE,39
2
2
  outerbounds/_vendor/PyYAML.LICENSE,sha256=jTko-dxEkP1jVwfLiOsmvXZBAqcoKVQwfT5RZ6V36KQ,1101
3
3
  outerbounds/_vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  outerbounds/_vendor/_yaml/__init__.py,sha256=nD985-g4Mrx97PhtSzI2L53o8sCHUJ4ZoBWcUd7o0PQ,1449
@@ -39,11 +39,13 @@ outerbounds/_vendor/yaml/resolver.py,sha256=dPhU1d7G1JCMktPFvNhyqwj2oNvx1yf_Jfa3
39
39
  outerbounds/_vendor/yaml/scanner.py,sha256=ZcI8IngR56PaQ0m27WU2vxCqmDCuRjz-hr7pirbMPuw,52982
40
40
  outerbounds/_vendor/yaml/serializer.py,sha256=8wFZRy9SsQSktF_f9OOroroqsh4qVUe53ry07P9UgCc,4368
41
41
  outerbounds/_vendor/yaml/tokens.py,sha256=JBSu38wihGr4l73JwbfMA7Ks1-X84g8-NskTz7KwPmA,2578
42
+ outerbounds/apps/__init__.py,sha256=oPp-ys_WWx_4xCQ_Yn7A23fIWVTiP2l_cpJ8jjFjNxU,678
42
43
  outerbounds/cli_main.py,sha256=e9UMnPysmc7gbrimq2I4KfltggyU7pw59Cn9aEguVcU,74
43
44
  outerbounds/command_groups/__init__.py,sha256=QPWtj5wDRTINDxVUL7XPqG3HoxHNvYOg08EnuSZB2Hc,21
44
- outerbounds/command_groups/apps_cli.py,sha256=v9OlQ1b4BGB-cBZiHB6W5gDocDoMmrQ7zdK11QiJ-B8,20847
45
- outerbounds/command_groups/cli.py,sha256=FTeeDrvyBb-qcs2xklTiCyVTN5I0tBPyBReqDIE4oWU,530
45
+ outerbounds/command_groups/apps_cli.py,sha256=fXwFjL64ZxlysFuJKoVmj5iX6tmHuU2hU5on2P0fCFc,20830
46
+ outerbounds/command_groups/cli.py,sha256=5xWLs-rp7QABrICWD-u13g8KCRLm9PwtHaJ6tmJzJvo,582
46
47
  outerbounds/command_groups/fast_bakery_cli.py,sha256=5kja7v6C651XAY6dsP_IkBPJQgfU4hA4S9yTOiVPhW0,6213
48
+ outerbounds/command_groups/flowprojects_cli.py,sha256=gFAA_zUIyhD092Hd7IW5InuIxOqdwRJsHgyWQjy8LZw,3792
47
49
  outerbounds/command_groups/kubernetes_cli.py,sha256=2bxPKUp5g_gdwVo4lT-IeWvHxz6Jmj1KxG70nXNgX_M,14758
48
50
  outerbounds/command_groups/local_setup_cli.py,sha256=tuuqJRXQ_guEwOuQSIf9wkUU0yg8yAs31myGViAK15s,36364
49
51
  outerbounds/command_groups/perimeters_cli.py,sha256=iF_Uw7ROiSctf6FgoJEy30iDBLVE1j9FKuR3shgJRmc,19050
@@ -56,7 +58,7 @@ outerbounds/utils/metaflowconfig.py,sha256=l2vJbgPkLISU-XPGZFaC8ZKmYFyJemlD6bwB-
56
58
  outerbounds/utils/schema.py,sha256=lMUr9kNgn9wy-sO_t_Tlxmbt63yLeN4b0xQXbDUDj4A,2331
57
59
  outerbounds/utils/utils.py,sha256=4Z8cszNob_8kDYCLNTrP-wWads_S_MdL3Uj3ju4mEsk,501
58
60
  outerbounds/vendor.py,sha256=gRLRJNXtZBeUpPEog0LOeIsl6GosaFFbCxUvR4bW6IQ,5093
59
- outerbounds-0.3.187.dist-info/METADATA,sha256=u0xNfL-xHTCs4NiK7pGPdl_MkGL-urd9SBjz-cjZ80U,1837
60
- outerbounds-0.3.187.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
61
- outerbounds-0.3.187.dist-info/entry_points.txt,sha256=7ye0281PKlvqxu15rjw60zKg2pMsXI49_A8BmGqIqBw,47
62
- outerbounds-0.3.187.dist-info/RECORD,,
61
+ outerbounds-0.3.188rc0.dist-info/METADATA,sha256=SZ1BegkoEFM7WFpoOBGlh6306zdwvnEcTTuHjl9QZOI,1846
62
+ outerbounds-0.3.188rc0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
63
+ outerbounds-0.3.188rc0.dist-info/entry_points.txt,sha256=AP6rZg7y5SK9e9a9iVq0Fi9Q2KPjPZSwtZ6R98rLw-8,56
64
+ outerbounds-0.3.188rc0.dist-info/RECORD,,
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ outerbounds=outerbounds.cli_main:cli
3
+
@@ -1,3 +0,0 @@
1
- [console_scripts]
2
- outerbounds=outerbounds:cli
3
-