outerbounds 0.3.51__py3-none-any.whl → 0.3.52rc0__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.
@@ -772,3 +772,372 @@ def configure(
772
772
  except Exception as e:
773
773
  click.secho("Writing the configuration file '{}' failed.".format(writer.path()))
774
774
  click.secho("Error: {}".format(str(e)))
775
+
776
+
777
+ @cli.command(help="Switch current perimeter")
778
+ @click.option(
779
+ "-o",
780
+ "--output",
781
+ default="",
782
+ help="Show output in the specified format.",
783
+ type=click.Choice(["json", ""]),
784
+ )
785
+ @click.option("--id", default="", help="Perimeter name to switch to")
786
+ @click.option(
787
+ "-f",
788
+ "--force",
789
+ is_flag=True,
790
+ help="Force change the existing perimeter",
791
+ default=False,
792
+ )
793
+ def switch_perimeter(output="", id=None, force=False):
794
+ switch_perimeter_response = OuterboundsCommandResponse()
795
+
796
+ switch_perimeter_step = CommandStatus(
797
+ "SwitchPerimeter",
798
+ OuterboundsCommandStatus.OK,
799
+ "Perimeter was successfully switched!",
800
+ )
801
+
802
+ if "WORKSTATION_ID" not in os.environ:
803
+ click.secho(
804
+ "outerbounds switch-perimeter is only supported on workstations.",
805
+ fg="red",
806
+ err=True,
807
+ )
808
+ switch_perimeter_step.update(
809
+ status=OuterboundsCommandStatus.FAIL,
810
+ reason="outerbounds switch-perimeter is only supported on workstations.",
811
+ mitigation="",
812
+ )
813
+ switch_perimeter_response.add_step(switch_perimeter_step)
814
+ if output == "json":
815
+ click.echo(json.dumps(switch_perimeter_response.as_dict(), indent=4))
816
+ return
817
+
818
+ metaflow_home_dir = path.expanduser(
819
+ os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")
820
+ )
821
+
822
+ if not os.path.exists("{}/config_{}.json".format(metaflow_home_dir, id)):
823
+ click.secho(
824
+ "Perimeter {} does not exist or you don't have access to it".format(id),
825
+ fg="red",
826
+ err=True,
827
+ )
828
+ switch_perimeter_step.update(
829
+ status=OuterboundsCommandStatus.FAIL,
830
+ reason="Perimeter {} does not exist or you don't have access to it".format(
831
+ id
832
+ ),
833
+ mitigation="Please contact your admin or the Outerbounds team for assistance.",
834
+ )
835
+ switch_perimeter_response.add_step(switch_perimeter_step)
836
+ if output == "json":
837
+ click.echo(json.dumps(switch_perimeter_response.as_dict(), indent=4))
838
+ return
839
+
840
+ # If OBP_CONFIG_DIR is set, use that, otherwise use METAFLOW_HOME
841
+ # If neither are set, use ~/.metaflowconfig
842
+ obp_config_dir = path.expanduser(
843
+ os.environ.get(
844
+ "OBP_CONFIG_DIR", os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")
845
+ )
846
+ )
847
+
848
+ path_to_config = os.path.expanduser(os.path.join(obp_config_dir, "ob_config.json"))
849
+
850
+ if not os.path.exists(path_to_config):
851
+ click.secho(
852
+ "Config file not found at {}".format(path_to_config), fg="red", err=True
853
+ )
854
+ switch_perimeter_step.update(
855
+ status=OuterboundsCommandStatus.FAIL,
856
+ reason="Config file not found",
857
+ mitigation="Please make sure the config file exists at {}".format(
858
+ path_to_config
859
+ ),
860
+ )
861
+ switch_perimeter_response.add_step(switch_perimeter_step)
862
+ if output == "json":
863
+ click.echo(json.dumps(switch_perimeter_response.as_dict(), indent=4))
864
+ return
865
+
866
+ import fcntl
867
+
868
+ fd = os.open(path_to_config, os.O_WRONLY)
869
+
870
+ try:
871
+ if not force:
872
+ # Try to acquire an exclusive lock
873
+ fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
874
+ else:
875
+ click.secho(
876
+ "Force flag is set. Perimeter will be switched, but can have unintended consequences on other running processes.",
877
+ fg="yellow",
878
+ )
879
+
880
+ ob_config_dict = {"OB_CURRENT_PERIMETER": id}
881
+
882
+ # Now that we have the lock, we can safely write to the file
883
+ with os.fdopen(fd, "w") as file:
884
+ json.dump(ob_config_dict, file, indent=4)
885
+
886
+ click.secho("Perimeter switched to {}".format(id), fg="green")
887
+ except BlockingIOError:
888
+ # This exception is raised if the file is already locked (non-blocking mode)
889
+ click.secho(
890
+ "Can't switch perimeter while Metaflow is in use. Please make sure there are no running python processes or notebooks using metaflow.",
891
+ fg="red",
892
+ err=True,
893
+ )
894
+ switch_perimeter_step.update(
895
+ status=OuterboundsCommandStatus.FAIL,
896
+ reason="Can't switch perimeter while Metaflow is in use.",
897
+ mitigation="Please make sure there are no running python processes or notebooks using metaflow.",
898
+ )
899
+
900
+ switch_perimeter_response.add_step(switch_perimeter_step)
901
+ if output == "json":
902
+ click.echo(json.dumps(switch_perimeter_response.as_dict(), indent=4))
903
+ return
904
+
905
+
906
+ @cli.command(help="Show current perimeter")
907
+ @click.option(
908
+ "-o",
909
+ "--output",
910
+ default="",
911
+ help="Show output in the specified format.",
912
+ type=click.Choice(["json", ""]),
913
+ )
914
+ def show_current_perimeter(output=""):
915
+ show_current_perimeter_response = OuterboundsCommandResponse()
916
+
917
+ show_current_perimeter_step = CommandStatus(
918
+ "ShowCurrentPerimeter",
919
+ OuterboundsCommandStatus.OK,
920
+ "Current Perimeter Fetch Successful.",
921
+ )
922
+
923
+ if "WORKSTATION_ID" not in os.environ:
924
+ click.secho(
925
+ "outerbounds switch-perimeter is only supported on workstations.",
926
+ fg="red",
927
+ err=True,
928
+ )
929
+ show_current_perimeter_step.update(
930
+ status=OuterboundsCommandStatus.FAIL,
931
+ reason="outerbounds show-current-perimeter is only supported on workstations.",
932
+ mitigation="",
933
+ )
934
+ show_current_perimeter_response.add_step(show_current_perimeter_step)
935
+ if output == "json":
936
+ click.echo(json.dumps(show_current_perimeter_response.as_dict(), indent=4))
937
+ return
938
+
939
+ metaflow_home_dir = path.expanduser(
940
+ os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")
941
+ )
942
+
943
+ # If OBP_CONFIG_DIR is set, use that, otherwise use METAFLOW_HOME
944
+ # If neither are set, use ~/.metaflowconfig
945
+ obp_config_dir = path.expanduser(
946
+ os.environ.get(
947
+ "OBP_CONFIG_DIR", os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")
948
+ )
949
+ )
950
+
951
+ path_to_config = os.path.expanduser(os.path.join(obp_config_dir, "ob_config.json"))
952
+
953
+ if not os.path.exists(path_to_config):
954
+ click.secho(
955
+ "Config file not found at {}".format(path_to_config), fg="red", err=True
956
+ )
957
+ show_current_perimeter_step.update(
958
+ status=OuterboundsCommandStatus.FAIL,
959
+ reason="Config file not found",
960
+ mitigation="Please make sure the config file exists at {}".format(
961
+ path_to_config
962
+ ),
963
+ )
964
+ show_current_perimeter_response.add_step(show_current_perimeter_step)
965
+ if output == "json":
966
+ click.echo(json.dumps(show_current_perimeter_response.as_dict(), indent=4))
967
+ return
968
+
969
+ with open(path_to_config, "r") as file:
970
+ ob_config_dict = json.load(file)
971
+
972
+ if "OB_CURRENT_PERIMETER" not in ob_config_dict:
973
+ click.secho(
974
+ "OB_CURRENT_PERIMETER not found in Config file: {}".format(path_to_config),
975
+ fg="red",
976
+ err=True,
977
+ )
978
+ show_current_perimeter_step.update(
979
+ status=OuterboundsCommandStatus.FAIL,
980
+ reason="OB_CURRENT_PERIMETER not found in Config file: {}",
981
+ mitigation="",
982
+ )
983
+ show_current_perimeter_response.add_step(show_current_perimeter_step)
984
+ if output == "json":
985
+ click.echo(json.dumps(show_current_perimeter_response.as_dict(), indent=4))
986
+ return
987
+
988
+ if os.path.exists(
989
+ os.path.join(
990
+ metaflow_home_dir,
991
+ "config_{}.json".format(ob_config_dict["OB_CURRENT_PERIMETER"]),
992
+ )
993
+ ):
994
+ click.secho(
995
+ "Current Perimeter: {}".format(ob_config_dict["OB_CURRENT_PERIMETER"]),
996
+ fg="green",
997
+ )
998
+ show_current_perimeter_response.add_or_update_data(
999
+ "current_perimeter", ob_config_dict["OB_CURRENT_PERIMETER"]
1000
+ )
1001
+ else:
1002
+ click.secho(
1003
+ "Perimeter config file not found at {}".format(
1004
+ os.path.join(
1005
+ metaflow_home_dir,
1006
+ "config_{}.json".format(ob_config_dict["OB_CURRENT_PERIMETER"]),
1007
+ )
1008
+ ),
1009
+ fg="red",
1010
+ err=True,
1011
+ )
1012
+ show_current_perimeter_step.update(
1013
+ status=OuterboundsCommandStatus.FAIL,
1014
+ reason="Perimeter config file not found",
1015
+ mitigation="Please make sure the perimeter config file exists at {}/config_{}.json".format(
1016
+ metaflow_home_dir, ob_config_dict["OB_CURRENT_PERIMETER"]
1017
+ ),
1018
+ )
1019
+ show_current_perimeter_response.add_step(show_current_perimeter_step)
1020
+
1021
+ if output == "json":
1022
+ click.echo(json.dumps(show_current_perimeter_response.as_dict(), indent=4))
1023
+
1024
+
1025
+ @cli.command(help="List all available perimeters")
1026
+ @click.option(
1027
+ "-o",
1028
+ "--output",
1029
+ default="",
1030
+ help="Show output in the specified format.",
1031
+ type=click.Choice(["json", ""]),
1032
+ )
1033
+ def list_perimeters(output=""):
1034
+ list_perimeters_response = OuterboundsCommandResponse()
1035
+
1036
+ list_perimeters_step = CommandStatus(
1037
+ "ListPerimeters", OuterboundsCommandStatus.OK, "Perimeter Fetch Successful."
1038
+ )
1039
+
1040
+ if "WORKSTATION_ID" not in os.environ:
1041
+ click.secho(
1042
+ "outerbounds list-perimeters is only supported on workstations.",
1043
+ fg="red",
1044
+ err=True,
1045
+ )
1046
+ list_perimeters_step.update(
1047
+ status=OuterboundsCommandStatus.FAIL,
1048
+ reason="outerbounds list-perimeters is only supported on workstations.",
1049
+ mitigation="",
1050
+ )
1051
+ list_perimeters_response.add_step(list_perimeters_step)
1052
+ if output == "json":
1053
+ click.echo(json.dumps(list_perimeters_response.as_dict(), indent=4))
1054
+ return
1055
+
1056
+ metaflow_home_dir = path.expanduser(
1057
+ os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")
1058
+ )
1059
+
1060
+ # If OBP_CONFIG_DIR is set, use that, otherwise use METAFLOW_HOME
1061
+ # If neither are set, use ~/.metaflowconfig
1062
+ obp_config_dir = path.expanduser(
1063
+ os.environ.get(
1064
+ "OBP_CONFIG_DIR", os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")
1065
+ )
1066
+ )
1067
+
1068
+ path_to_config = os.path.expanduser(os.path.join(obp_config_dir, "ob_config.json"))
1069
+
1070
+ if not os.path.exists(path_to_config):
1071
+ click.secho(
1072
+ "Config file not found at {}".format(path_to_config), fg="red", err=True
1073
+ )
1074
+ list_perimeters_step.update(
1075
+ status=OuterboundsCommandStatus.FAIL,
1076
+ reason="Config file not found",
1077
+ mitigation="Please make sure the config file exists at {}".format(
1078
+ path_to_config
1079
+ ),
1080
+ )
1081
+ list_perimeters_response.add_step(list_perimeters_step)
1082
+ if output == "json":
1083
+ click.echo(json.dumps(list_perimeters_response.as_dict(), indent=4))
1084
+ return
1085
+
1086
+ with open(path_to_config, "r") as file:
1087
+ ob_config_dict = json.load(file)
1088
+
1089
+ if "OB_CURRENT_PERIMETER" not in ob_config_dict:
1090
+ click.secho(
1091
+ "OB_CURRENT_PERIMETER not found in Config file: {}".format(path_to_config),
1092
+ fg="red",
1093
+ err=True,
1094
+ )
1095
+ list_perimeters_step.update(
1096
+ status=OuterboundsCommandStatus.FAIL,
1097
+ reason="OB_CURRENT_PERIMETER not found in Config file: {}",
1098
+ mitigation="",
1099
+ )
1100
+ list_perimeters_response.add_step(list_perimeters_step)
1101
+ if output == "json":
1102
+ click.echo(json.dumps(list_perimeters_response.as_dict(), indent=4))
1103
+ return
1104
+
1105
+ if os.path.exists(
1106
+ os.path.join(
1107
+ metaflow_home_dir,
1108
+ "config_{}.json".format(ob_config_dict["OB_CURRENT_PERIMETER"]),
1109
+ )
1110
+ ):
1111
+ active_perimeter = ob_config_dict["OB_CURRENT_PERIMETER"]
1112
+ else:
1113
+ click.secho(
1114
+ "Perimeter config file not found at {}".format(
1115
+ os.path.join(
1116
+ metaflow_home_dir,
1117
+ "config_{}.json".format(ob_config_dict["OB_CURRENT_PERIMETER"]),
1118
+ )
1119
+ ),
1120
+ fg="red",
1121
+ err=True,
1122
+ )
1123
+ list_perimeters_step.update(
1124
+ status=OuterboundsCommandStatus.FAIL,
1125
+ reason="Perimeter config file not found",
1126
+ mitigation="Please make sure the perimeter config file exists at {}/config_{}.json".format(
1127
+ metaflow_home_dir, ob_config_dict["OB_CURRENT_PERIMETER"]
1128
+ ),
1129
+ )
1130
+ list_perimeters_response.add_step(list_perimeters_step)
1131
+ return
1132
+
1133
+ perimeter_list = []
1134
+ for file in os.listdir(metaflow_home_dir):
1135
+ if file.startswith("config_") and file.endswith(".json"):
1136
+ perimeter_id = file.split("_")[1].split(".")[0]
1137
+ perimeter_list.append(
1138
+ {"id": perimeter_id, "active": perimeter_id == active_perimeter}
1139
+ )
1140
+
1141
+ list_perimeters_response.add_or_update_data("perimeters", perimeter_list)
1142
+ if output == "json":
1143
+ click.echo(json.dumps(list_perimeters_response.as_dict(), indent=4))
@@ -37,10 +37,14 @@ class OuterboundsCommandResponse:
37
37
  self._message = ""
38
38
  self._steps = []
39
39
  self.metadata = {}
40
+ self._data = {}
40
41
 
41
42
  def add_or_update_metadata(self, key, value):
42
43
  self.metadata[key] = value
43
44
 
45
+ def add_or_update_data(self, key, value):
46
+ self._data[key] = value
47
+
44
48
  def add_step(self, step: CommandStatus):
45
49
  self._steps.append(step)
46
50
  self._process_step_status(step)
@@ -65,4 +69,5 @@ class OuterboundsCommandResponse:
65
69
  "message": self._message,
66
70
  "steps": [step.as_dict() for step in self._steps],
67
71
  "metadata": self.metadata,
72
+ "data": self._data,
68
73
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: outerbounds
3
- Version: 0.3.51
3
+ Version: 0.3.52rc0
4
4
  Summary: More Data Science, Less Administration
5
5
  License: Proprietary
6
6
  Keywords: data science,machine learning,MLOps
@@ -14,17 +14,13 @@ Classifier: Programming Language :: Python :: 3.9
14
14
  Classifier: Programming Language :: Python :: 3.10
15
15
  Classifier: Programming Language :: Python :: 3.11
16
16
  Provides-Extra: azure
17
- Provides-Extra: gcp
18
17
  Requires-Dist: PyYAML (>=6.0,<7.0)
19
18
  Requires-Dist: azure-identity (>=1.15.0,<2.0.0) ; extra == "azure"
20
19
  Requires-Dist: azure-storage-blob (>=12.9.0,<13.0.0) ; extra == "azure"
21
20
  Requires-Dist: boto3
22
21
  Requires-Dist: click (>=8.1.3,<9.0.0)
23
- Requires-Dist: google-api-core (>=2.16.1,<3.0.0) ; extra == "gcp"
24
- Requires-Dist: google-auth (>=2.27.0,<3.0.0) ; extra == "gcp"
25
- Requires-Dist: google-cloud-storage (>=2.14.0,<3.0.0) ; extra == "gcp"
26
- Requires-Dist: ob-metaflow (==2.11.0.4)
27
- Requires-Dist: ob-metaflow-extensions (==1.1.42)
22
+ Requires-Dist: ob-metaflow (==2.11.0.3)
23
+ Requires-Dist: ob-metaflow-extensions (==1.1.42rc0)
28
24
  Requires-Dist: opentelemetry-distro (==0.41b0)
29
25
  Requires-Dist: opentelemetry-exporter-otlp-proto-http (==1.20.0)
30
26
  Requires-Dist: opentelemetry-instrumentation-requests (==0.41b0)
@@ -2,13 +2,13 @@ outerbounds/__init__.py,sha256=GPdaubvAYF8pOFWJ3b-sPMKCpyfpteWVMZWkmaYhxRw,32
2
2
  outerbounds/cli_main.py,sha256=e9UMnPysmc7gbrimq2I4KfltggyU7pw59Cn9aEguVcU,74
3
3
  outerbounds/command_groups/__init__.py,sha256=QPWtj5wDRTINDxVUL7XPqG3HoxHNvYOg08EnuSZB2Hc,21
4
4
  outerbounds/command_groups/cli.py,sha256=61VsBlPG2ykP_786eCyllqeM8DMhPAOfj2FhktrSd7k,207
5
- outerbounds/command_groups/local_setup_cli.py,sha256=5S1bcq8mW5YS-PZBO4ZrBAeLwFqcQYmm_t9ALjT77nU,28312
5
+ outerbounds/command_groups/local_setup_cli.py,sha256=HOTvOlb22cF86QmDpdQc6UVx4gFa2hBzsM8qI7Yj6vY,41486
6
6
  outerbounds/command_groups/workstations_cli.py,sha256=VgydQzCas3mlAFyzZuanjl1E8Zh7pBrbKbbP6t6N2WU,18237
7
7
  outerbounds/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  outerbounds/utils/kubeconfig.py,sha256=l1mUP1j9VIq3fsffi5bJ1Nk-hYlwd1dIqkpj7DvVS1E,7936
9
9
  outerbounds/utils/metaflowconfig.py,sha256=zdSeZEc1h4yJAZUrfWIO9EYSy84wdE_JCSEiCxb-su8,2341
10
- outerbounds/utils/schema.py,sha256=nBuarFbdZu0LGhG0YkJ6pEIvdglfM_TO_W_Db2vksb0,2017
11
- outerbounds-0.3.51.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
12
- outerbounds-0.3.51.dist-info/entry_points.txt,sha256=7ye0281PKlvqxu15rjw60zKg2pMsXI49_A8BmGqIqBw,47
13
- outerbounds-0.3.51.dist-info/METADATA,sha256=WAr8ATcx7tGjEu5BMi8yGFU5Er2BiYSqwgFo4X-7yVc,1361
14
- outerbounds-0.3.51.dist-info/RECORD,,
10
+ outerbounds/utils/schema.py,sha256=4_ONlvZGpBb51KKd-q6mNSKWI9P1huOKafrsf9kVqp8,2152
11
+ outerbounds-0.3.52rc0.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
12
+ outerbounds-0.3.52rc0.dist-info/entry_points.txt,sha256=7ye0281PKlvqxu15rjw60zKg2pMsXI49_A8BmGqIqBw,47
13
+ outerbounds-0.3.52rc0.dist-info/METADATA,sha256=xkqrbbaDvrjERYy5fZ0kqk8Y_TEGneAjF5H0e6-uiNs,1148
14
+ outerbounds-0.3.52rc0.dist-info/RECORD,,