ob-metaflow-extensions 1.1.175rc1__py2.py3-none-any.whl → 1.1.175rc3__py2.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.

Potentially problematic release.


This version of ob-metaflow-extensions might be problematic. Click here for more details.

Files changed (28) hide show
  1. metaflow_extensions/outerbounds/plugins/__init__.py +1 -1
  2. metaflow_extensions/outerbounds/plugins/apps/app_deploy_decorator.py +112 -0
  3. metaflow_extensions/outerbounds/plugins/apps/core/__init__.py +9 -0
  4. metaflow_extensions/outerbounds/plugins/apps/core/app_cli.py +42 -374
  5. metaflow_extensions/outerbounds/plugins/apps/core/app_config.py +45 -225
  6. metaflow_extensions/outerbounds/plugins/apps/core/capsule.py +22 -6
  7. metaflow_extensions/outerbounds/plugins/apps/core/code_package/code_packager.py +16 -15
  8. metaflow_extensions/outerbounds/plugins/apps/core/config/__init__.py +12 -0
  9. metaflow_extensions/outerbounds/plugins/apps/core/config/cli_generator.py +161 -0
  10. metaflow_extensions/outerbounds/plugins/apps/core/config/config_utils.py +828 -0
  11. metaflow_extensions/outerbounds/plugins/apps/core/config/schema_export.py +285 -0
  12. metaflow_extensions/outerbounds/plugins/apps/core/config/typed_configs.py +104 -0
  13. metaflow_extensions/outerbounds/plugins/apps/core/config/typed_init_generator.py +317 -0
  14. metaflow_extensions/outerbounds/plugins/apps/core/config/unified_config.py +994 -0
  15. metaflow_extensions/outerbounds/plugins/apps/core/config_schema.yaml +217 -211
  16. metaflow_extensions/outerbounds/plugins/apps/core/dependencies.py +3 -3
  17. metaflow_extensions/outerbounds/plugins/apps/core/deployer.py +132 -0
  18. metaflow_extensions/outerbounds/plugins/apps/core/experimental/__init__.py +4 -36
  19. metaflow_extensions/outerbounds/plugins/apps/core/perimeters.py +44 -2
  20. metaflow_extensions/outerbounds/plugins/apps/core/validations.py +4 -9
  21. metaflow_extensions/outerbounds/toplevel/global_aliases_for_metaflow_package.py +1 -0
  22. metaflow_extensions/outerbounds/toplevel/ob_internal.py +1 -0
  23. {ob_metaflow_extensions-1.1.175rc1.dist-info → ob_metaflow_extensions-1.1.175rc3.dist-info}/METADATA +1 -1
  24. {ob_metaflow_extensions-1.1.175rc1.dist-info → ob_metaflow_extensions-1.1.175rc3.dist-info}/RECORD +26 -20
  25. metaflow_extensions/outerbounds/plugins/apps/core/cli_to_config.py +0 -99
  26. metaflow_extensions/outerbounds/plugins/apps/core/config_schema_autogen.json +0 -336
  27. {ob_metaflow_extensions-1.1.175rc1.dist-info → ob_metaflow_extensions-1.1.175rc3.dist-info}/WHEEL +0 -0
  28. {ob_metaflow_extensions-1.1.175rc1.dist-info → ob_metaflow_extensions-1.1.175rc3.dist-info}/top_level.txt +0 -0
@@ -1,269 +1,275 @@
1
-
2
- title: Outerbounds App Configuration Schema
1
+ $schema: https://json-schema.org/draft/2020-12/schema
2
+ title: CoreConfig
3
3
  description: |
4
4
  Schema for defining Outerbounds Apps configuration. This schema is what we will end up using on the CLI/programmatic interface.
5
5
  How to read this schema:
6
- 1. If the a property has `allow_union`:true then it will allow overrides from the cli.
7
- 2. If a property has `experimental` set to true then a lot its validations may-be skipped and parsing handled somewhere else.
8
-
9
- The YAML based schema file is for Humans to change and consume. The JSON based schema file is what gets autogenerated based on pre-commit
10
- hooks so that we can use within the outerbounds package. The reasons for two distinct types of files it that YAML provides the ability to
11
- add comments and make readability easier. While JSON is so that we can reduce the dependency on YAML when working with apps within both
12
- Metaflow and OB package.
13
- version: 1.0.0
6
+ 1. If the a property has `mutation_behavior` set to `union` then it will allow overrides of values at runtime from the CLI.
7
+ 2. If the property has `mutation_behavior`set to `not_allowed` then either the CLI or the config file value will be used (which ever is not None). If the user supplies something in both then an error will be raised.
8
+ 3. If a property has `experimental` set to true then a lot its validations may-be skipped and parsing handled somewhere else.
14
9
  type: object
15
10
  required:
16
- - name
17
- - port
11
+ - name
12
+ - port
13
+ - commands
18
14
  properties:
19
- name: # Only used in `deploy` command
20
- allow_union: true # Allow overriding name from the CLI.
15
+ name:
16
+ description: The name of the app to deploy. (validation applied)
21
17
  type: string
22
- description: The name of the app to deploy.
23
- maxLength: 20 # todo: check if we should allow a larger length.
24
- example: "myapp"
25
- port: # Only used in `deploy` command
26
- allow_union: false
18
+ example: myapp
19
+ mutation_behavior: union
20
+ port:
21
+ description: |-
22
+ Port where the app is hosted. When deployed this will be port on which we will deploy the app. (validation applied)
27
23
  type: integer
28
- description: Port where the app is hosted. When deployed this will be port on which we will deploy the app.
29
- minimum: 1
30
- maximum: 65535
31
24
  example: 8000
32
- tags: # Only used in `deploy` command
33
- allow_union: true
34
- type: array
35
- description: The tags of the app to deploy.
36
- items:
37
- type: object
38
- example:
39
- - foo: bar
40
- - x: y
41
- description: # Only used in `deploy` command
42
- allow_union: true
43
- type: string
25
+ mutation_behavior: union
26
+ description:
44
27
  description: The description of the app to deploy.
45
- example: "This is a description of my app."
46
- force_upgrade: # Only used in `deploy` command
47
- allow_union: true
48
- type: boolean
49
- description: Whether to force upgrade the app even if it is currently being upgraded.
50
- example: true
51
- app_type: # Only used in `deploy` command
52
- allow_union: true
53
28
  type: string
29
+ example: This is a description of my app.
30
+ mutation_behavior: union
31
+ app_type:
54
32
  description: The User defined type of app to deploy. Its only used for bookkeeping purposes.
55
- example: "MyCustomAgent"
56
- image: # Only used in `deploy` command
57
- allow_union: true # We will overrwite the image if specified on the CLI.
58
33
  type: string
34
+ example: MyCustomAgent
35
+ mutation_behavior: union
36
+ image:
59
37
  description: The Docker image to deploy with the App.
60
- secrets: # Used in `run` command
61
- allow_union: true
38
+ type: string
39
+ example: python:3.10-slim
40
+ mutation_behavior: union
41
+ tags:
42
+ description: The tags of the app to deploy. (validation applied)
62
43
  type: array
63
- description: Outerbounds integrations to attach to the app. You can use the value you set in the `@secrets` decorator in your code.
64
44
  items:
65
45
  type: string
66
- example: ["hf-token"]
67
- environment: # Used in `run` command
68
- # Todo: So this part might not be best on the CLI. We should probably have a better way to handle this.
69
- # In simplicity, we can just JSON dump anything that looks like a dict/list/
70
- allow_union: true
71
- type: object
46
+ example:
47
+ - foo: bar
48
+ - x: y
49
+ mutation_behavior: union
50
+ secrets:
51
+ description: |-
52
+ Outerbounds integrations to attach to the app. You can use the value you set in the `@secrets` decorator in your code. (validation applied)
53
+ type: array
54
+ items:
55
+ type: string
56
+ example:
57
+ - hf-token
58
+ mutation_behavior: union
59
+ compute_pools:
60
+ description: A list of compute pools to deploy the app to.
61
+ type: array
62
+ items:
63
+ type: string
64
+ example:
65
+ - default
66
+ - large
67
+ mutation_behavior: union
68
+ environment:
72
69
  description: Environment variables to deploy with the App.
73
- additionalProperties:
74
- oneOf:
75
- - type: string
76
- - type: number
77
- - type: boolean
78
- - type: object
79
- - type: array # When users give arrays, or objects, we need to JSON dump them. Users need to be aware of this.
70
+ type: object
71
+ additionalProperties: true
80
72
  example:
81
73
  DEBUG: true
82
- DATABASE_CONFIG: {"host": "localhost", "port": 5432}
83
- ALLOWED_ORIGINS: ["http://localhost:3000", "https://myapp.com"]
84
- dependencies: # Used in `run` command
85
- allow_union: false
86
- type: object
87
- description: |
88
- The dependencies to attach to the app. Only one of the properties can be specified.
89
- properties:
90
- from_requirements_file:
91
- type: string
92
- description: The path to the requirements.txt file to attach to the app.
93
- example: "requirements.txt"
94
- from_pyproject_toml:
95
- type: string
96
- description: The path to the pyproject.toml file to attach to the app.
97
- example: "pyproject.toml"
98
- python:
99
- type: string
100
- description: |
101
- The Python version to use for the app.
102
- example: "3.10"
103
- pypi:
104
- type: object
105
- description: |
106
- A dictionary of pypi dependencies to attach to the app.
107
- The key is the package name and the value is the version.
108
- example:
109
- numpy: 1.23.0
110
- pandas: ""
111
- conda:
112
- type: object
113
- description: |
114
- A dictionary of pypi dependencies to attach to the app.
115
- The key is the package name and the value is the version.
116
- example:
117
- numpy: 1.23.0
118
- pandas: ""
119
- package:
120
- allow_union: false
121
- type: object
122
- description: |
123
- Configurations associated with packaging the app.
124
- properties:
125
- src_path:
126
- type: string
127
- description: The path to the source code to deploy with the App.
128
- example: "./"
129
- suffixes:
130
- type: array
131
- description: |
132
- A list of suffixes to add to the source code to deploy with the App.
133
- items:
134
- type: string
135
- example: [".py", ".ipynb"]
136
-
137
- commands: # Used in `run` command
138
- allow_union: false
74
+ DATABASE_CONFIG:
75
+ host: localhost
76
+ port: 5432
77
+ ALLOWED_ORIGINS:
78
+ - http://localhost:3000
79
+ - https://myapp.com
80
+ mutation_behavior: union
81
+ commands:
82
+ description: A list of commands to run the app with.
139
83
  type: array
140
- description: A list of commands to run the app with. Cannot be configured from the CLI. Only used in `run` command.
141
84
  items:
142
85
  type: string
143
- example: ["python app.py", "python app.py --foo bar"]
144
- resources: # Only used in `deploy` command
145
- allow_union: true # You can override CPU/Memory/GPU/Storage from the CLI.
86
+ example:
87
+ - python app.py
88
+ - python app.py --foo bar
89
+ mutation_behavior: not_allowed
90
+ resources:
91
+ title: ResourceConfig
92
+ description: Resource configuration for the app.
146
93
  type: object
94
+ required: []
147
95
  properties:
148
96
  cpu:
97
+ description: CPU resource request and limit. (validation applied)
149
98
  type: string
150
- description: CPU resource request and limit.
151
- example: "500m"
152
- default: "1"
99
+ default: '1'
100
+ example: 500m
101
+ mutation_behavior: union
153
102
  memory:
103
+ description: Memory resource request and limit. (validation applied)
154
104
  type: string
155
- description: Memory resource request and limit.
156
- example: "512Mi"
157
- default: "4Gi"
105
+ default: 4Gi
106
+ example: 512Mi
107
+ mutation_behavior: union
158
108
  gpu:
109
+ description: GPU resource request and limit. (validation applied)
159
110
  type: string
160
- description: GPU resource request and limit.
161
- example: "1"
111
+ example: '1'
112
+ mutation_behavior: union
162
113
  disk:
114
+ description: Storage resource request and limit. (validation applied)
163
115
  type: string
164
- description: Storage resource request and limit.
165
- example: "1Gi"
166
- default: "20Gi"
116
+ default: 20Gi
117
+ example: 1Gi
118
+ mutation_behavior: union
119
+ mutation_behavior: union
120
+ auth:
121
+ title: AuthConfig
122
+ description: Authentication configuration.
123
+ type: object
124
+ required: []
125
+ properties:
126
+ type:
127
+ description: The type of authentication to use for the app.
128
+ type: string
129
+ default: Browser
130
+ enum:
131
+ - Browser
132
+ - API
133
+ example: Browser
134
+ mutation_behavior: union
135
+ public:
136
+ description: Whether the app is public or not.
137
+ type: boolean
138
+ default: true
139
+ example: true
140
+ mutation_behavior: union
141
+ mutation_behavior: union
167
142
  replicas:
168
- allow_union: true
143
+ title: ReplicaConfig
144
+ description: Replica configuration.
169
145
  type: object
170
- description: |
171
- The number of replicas to deploy the app with.
146
+ required: []
172
147
  properties:
173
- min:
148
+ fixed:
149
+ description: |-
150
+ The fixed number of replicas to deploy the app with. If min and max are set, this will raise an error.
174
151
  type: integer
152
+ example: 1
153
+ mutation_behavior: union
154
+ min:
175
155
  description: The minimum number of replicas to deploy the app with.
156
+ type: integer
176
157
  example: 1
158
+ mutation_behavior: union
177
159
  max:
178
- type: integer
179
160
  description: The maximum number of replicas to deploy the app with.
161
+ type: integer
180
162
  example: 10
181
- health_check: # Can be used in `run` command
163
+ mutation_behavior: union
164
+ mutation_behavior: union
165
+ dependencies:
166
+ title: DependencyConfig
167
+ description: Dependency configuration.
182
168
  type: object
183
- # `allow_union` property means that any object in this field will be done a union with the config file if something is provided on commanline.
184
- # If it is set to false, then we should throw an exception if the CLI is trying to override something specified in the config file.
185
- # We will only allow unions in certains options. The rest will not allow any unions and only need to be specified in one place.
186
- allow_union: false
169
+ required: []
187
170
  properties:
188
- enabled:
189
- type: boolean
190
- description: Whether to enable health checks.
191
- example: true
192
- default: false
193
- path:
171
+ from_requirements_file:
172
+ description: The path to the requirements.txt file to attach to the app.
194
173
  type: string
195
- description: The path for health checks.
196
- example: "/health"
197
- initial_delay_seconds:
198
- type: integer
199
- description: Number of seconds to wait before performing the first health check.
200
- example: 10
201
- period_seconds:
202
- type: integer
203
- description: How often to perform the health check.
204
- example: 30
205
- compute_pools: # Only used in `deploy` command
206
- allow_union: true
207
- type: array
208
- description: |
209
- A list of compute pools to deploy the app to.
210
- items:
211
- type: string
212
- example: ["default", "large"]
213
- auth: # Only used in `deploy` command
214
- allow_union: false
174
+ example: requirements.txt
175
+ mutation_behavior: not_allowed
176
+ from_pyproject_toml:
177
+ description: The path to the pyproject.toml file to attach to the app.
178
+ type: string
179
+ example: pyproject.toml
180
+ mutation_behavior: not_allowed
181
+ python:
182
+ description: The Python version to use for the app.
183
+ type: string
184
+ example: '3.10'
185
+ mutation_behavior: not_allowed
186
+ pypi:
187
+ description: |-
188
+ A dictionary of pypi dependencies to attach to the app. The key is the package name and the value is the version.
189
+ type: object
190
+ additionalProperties: true
191
+ example:
192
+ numpy: 1.23.0
193
+ pandas: ''
194
+ mutation_behavior: not_allowed
195
+ conda:
196
+ description: |-
197
+ A dictionary of conda dependencies to attach to the app. The key is the package name and the value is the version.
198
+ type: object
199
+ additionalProperties: true
200
+ example:
201
+ numpy: 1.23.0
202
+ pandas: ''
203
+ mutation_behavior: not_allowed
204
+ mutation_behavior: union
205
+ package:
206
+ title: PackageConfig
207
+ description: Package configuration.
215
208
  type: object
216
- description: |
217
- Auth related configurations.
209
+ required: []
218
210
  properties:
219
- type:
211
+ src_path:
212
+ description: The path to the source code to deploy with the App.
220
213
  type: string
221
- description: |
222
- The type of authentication to use for the app.
223
- enum: [API, Browser]
224
- public:
225
- type: boolean
226
- description: |
227
- Whether the app is public or not.
228
- default: true
229
- # There is an allowed perimeters property
230
- # But that needs a little more thought on how
231
- # to expose.
232
-
233
- # ------------------------------------ EXPERIMENTAL ------------------------------------
234
- project:
214
+ example: ./
215
+ mutation_behavior: union
216
+ suffixes:
217
+ description: A list of suffixes to add to the source code to deploy with the App.
218
+ type: array
219
+ items:
220
+ type: string
221
+ example:
222
+ - .py
223
+ - .ipynb
224
+ mutation_behavior: union
225
+ mutation_behavior: union
226
+ no_deps:
227
+ description: Do not bake any dependencies. Directly used the image provided
228
+ type: boolean
229
+ default: false
230
+ mutation_behavior: union
231
+ force_upgrade:
232
+ description: Force upgrade the app even if it is currently being upgraded.
233
+ type: boolean
234
+ default: false
235
+ mutation_behavior: union
236
+ persistence:
237
+ description: The persistence mode to deploy the app with. (validation applied)
235
238
  type: string
239
+ default: none
240
+ enum:
241
+ - none
242
+ - postgres
243
+ example: postgres
244
+ experimental: true
245
+ mutation_behavior: union
246
+ project:
236
247
  description: The project name to deploy the app to.
248
+ type: string
249
+ example: my-project
237
250
  experimental: true
238
- allow_union: true
251
+ mutation_behavior: union
239
252
  branch:
240
- type: string
241
253
  description: The branch name to deploy the app to.
254
+ type: string
255
+ example: main
242
256
  experimental: true
243
- allow_union: true
244
-
245
- models: #
257
+ mutation_behavior: union
258
+ models:
246
259
  type: array
247
- description: model asset ids to include with the deployment. NO CLI Option for this Now.
248
- experimental: true
249
- allow_union: true
250
260
  items:
251
- type: object
252
- properties:
253
- asset_id:
254
- type: string
255
- asset_instance_id:
256
- type: string
257
- data: #
258
- type: array
259
- description: data asset ids to include with the deployment.
261
+ type: string
262
+ example:
263
+ - asset_id: model-123
264
+ asset_instance_id: instance-456
260
265
  experimental: true
261
- allow_union: true
266
+ mutation_behavior: union
267
+ data:
268
+ type: array
262
269
  items:
263
- type: object
264
- properties:
265
- asset_id:
266
- type: string
267
- asset_instance_id:
268
- type: string
269
- # ------------------------------------ EXPERIMENTAL ------------------------------------
270
+ type: string
271
+ example:
272
+ - asset_id: data-789
273
+ asset_instance_id: instance-101
274
+ experimental: true
275
+ mutation_behavior: union
@@ -73,12 +73,12 @@ def bake_deployment_image(
73
73
  python_version = parsed_packages.get("python_version", python_version)
74
74
 
75
75
  elif "pypi" in dependencies:
76
- pypi_packages = dependencies.get("pypi", {})
76
+ pypi_packages = dependencies.get("pypi", {}) or {}
77
77
 
78
78
  if "conda" in dependencies:
79
- conda_packages = dependencies.get("conda", {})
79
+ conda_packages = dependencies.get("conda", {}) or {}
80
80
  if "python" in dependencies:
81
- python_version = dependencies.get("python", python_version)
81
+ python_version = dependencies.get("python", python_version) or python_version
82
82
 
83
83
  python_packages_exist = len(pypi_packages) > 0 or len(conda_packages) > 0
84
84
  if (not python_packages_exist) or app_config.get_state("skip_dependencies", False):
@@ -0,0 +1,132 @@
1
+ from .config import TypedCoreConfig
2
+
3
+ from ._state_machine import DEPLOYMENT_READY_CONDITIONS
4
+ from .app_config import AppConfig, AppConfigError
5
+ from .capsule import CapsuleDeployer, list_and_filter_capsules
6
+ from functools import partial
7
+ import sys
8
+ from typing import Type
9
+
10
+
11
+ class AppDeployer(TypedCoreConfig):
12
+ """ """
13
+
14
+ __init__ = TypedCoreConfig.__init__
15
+
16
+ _app_config: AppConfig
17
+
18
+ _state = {}
19
+
20
+ @property
21
+ def app_config(self) -> AppConfig:
22
+ if not hasattr(self, "_app_config"):
23
+ self._app_config = AppConfig(self._config)
24
+ return self._app_config
25
+
26
+ # Things that need to be set before deploy
27
+ @classmethod
28
+ def _set_state(
29
+ cls,
30
+ perimeter: str,
31
+ api_url: str,
32
+ code_package_url: str = None,
33
+ code_package_key: str = None,
34
+ name: str = None,
35
+ image: str = None,
36
+ ):
37
+ cls._state["perimeter"] = perimeter
38
+ cls._state["api_url"] = api_url
39
+ cls._state["code_package_url"] = code_package_url
40
+ cls._state["code_package_key"] = code_package_key
41
+ cls._state["name"] = name
42
+ cls._state["image"] = image
43
+
44
+ def deploy(
45
+ self,
46
+ readiness_condition=DEPLOYMENT_READY_CONDITIONS.ATLEAST_ONE_RUNNING,
47
+ max_wait_time=600,
48
+ readiness_wait_time=10,
49
+ logger_fn=partial(print, file=sys.stderr),
50
+ status_file=None,
51
+ no_loader=False,
52
+ **kwargs,
53
+ ):
54
+ # Name setting from top level if none is set in the code
55
+ if self.app_config._core_config.name is None:
56
+ self.app_config._core_config.name = self._state["name"]
57
+
58
+ self.app_config.commit()
59
+
60
+ # Set any state that might have been passed down from the top level
61
+ for k, v in self._state.items():
62
+ if self.app_config.get_state(k) is None:
63
+ self.app_config.set_state(k, v)
64
+
65
+ capsule = CapsuleDeployer(
66
+ self.app_config,
67
+ self._state["api_url"],
68
+ create_timeout=max_wait_time,
69
+ debug_dir=None,
70
+ success_terminal_state_condition=readiness_condition,
71
+ readiness_wait_time=readiness_wait_time,
72
+ logger_fn=logger_fn,
73
+ )
74
+
75
+ currently_present_capsules = list_and_filter_capsules(
76
+ capsule.capsule_api,
77
+ None,
78
+ None,
79
+ capsule.name,
80
+ None,
81
+ None,
82
+ None,
83
+ )
84
+
85
+ force_upgrade = self.app_config.get_state("force_upgrade", False)
86
+
87
+ if len(currently_present_capsules) > 0:
88
+ # Only update the capsule if there is no upgrade in progress
89
+ # Only update a "already updating" capsule if the `--force-upgrade` flag is provided.
90
+ _curr_cap = currently_present_capsules[0]
91
+ this_capsule_is_being_updated = _curr_cap.get("status", {}).get(
92
+ "updateInProgress", False
93
+ )
94
+
95
+ if this_capsule_is_being_updated and not force_upgrade:
96
+ _upgrader = _curr_cap.get("metadata", {}).get("lastModifiedBy", None)
97
+ message = f"{capsule.capsule_type} is currently being upgraded"
98
+ if _upgrader:
99
+ message = (
100
+ f"{capsule.capsule_type} is currently being upgraded. Upgrade was launched by {_upgrader}. "
101
+ "If you wish to force upgrade, you can do so by providing the `--force-upgrade` flag."
102
+ )
103
+ raise AppConfigError(message)
104
+
105
+ logger_fn(
106
+ f"🚀 {'' if not force_upgrade else 'Force'} Upgrading {capsule.capsule_type.lower()} `{capsule.name}`....",
107
+ )
108
+ else:
109
+ logger_fn(
110
+ f"🚀 Deploying {capsule.capsule_type.lower()} `{capsule.name}`....",
111
+ )
112
+
113
+ capsule.create()
114
+ final_status = capsule.wait_for_terminal_state()
115
+ return final_status
116
+
117
+
118
+ class apps:
119
+
120
+ _name_prefix = None
121
+
122
+ @classmethod
123
+ def set_name_prefix(cls, name_prefix: str):
124
+ cls._name_prefix = name_prefix
125
+
126
+ @property
127
+ def name_prefix(self) -> str:
128
+ return self._name_prefix
129
+
130
+ @property
131
+ def Deployer(self) -> Type[AppDeployer]:
132
+ return AppDeployer