outerbounds 0.3.186__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 +3 -1
- outerbounds/apps/__init__.py +28 -0
- outerbounds/command_groups/apps_cli.py +2 -6
- outerbounds/command_groups/cli.py +2 -0
- outerbounds/command_groups/flowprojects_cli.py +137 -0
- {outerbounds-0.3.186.dist-info → outerbounds-0.3.188rc0.dist-info}/METADATA +3 -3
- {outerbounds-0.3.186.dist-info → outerbounds-0.3.188rc0.dist-info}/RECORD +9 -7
- outerbounds-0.3.188rc0.dist-info/entry_points.txt +3 -0
- outerbounds-0.3.186.dist-info/entry_points.txt +0 -3
- {outerbounds-0.3.186.dist-info → outerbounds-0.3.188rc0.dist-info}/WHEEL +0 -0
outerbounds/__init__.py
CHANGED
@@ -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
|
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.
|
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.
|
33
|
-
Requires-Dist: ob-metaflow-stubs (==6.0.3.
|
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=
|
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=
|
45
|
-
outerbounds/command_groups/cli.py,sha256=
|
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.
|
60
|
-
outerbounds-0.3.
|
61
|
-
outerbounds-0.3.
|
62
|
-
outerbounds-0.3.
|
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,,
|
File without changes
|