nextmv 0.27.0__py3-none-any.whl → 0.28.1__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.
- nextmv/__about__.py +1 -1
- nextmv/__init__.py +1 -0
- nextmv/base_model.py +52 -7
- nextmv/cloud/__init__.py +3 -0
- nextmv/cloud/acceptance_test.py +711 -20
- nextmv/cloud/account.py +152 -7
- nextmv/cloud/application.py +1213 -382
- nextmv/cloud/batch_experiment.py +133 -21
- nextmv/cloud/client.py +240 -46
- nextmv/cloud/input_set.py +96 -3
- nextmv/cloud/instance.py +89 -3
- nextmv/cloud/manifest.py +508 -132
- nextmv/cloud/package.py +2 -2
- nextmv/cloud/run.py +372 -41
- nextmv/cloud/safe.py +7 -7
- nextmv/cloud/scenario.py +205 -20
- nextmv/cloud/secrets.py +179 -6
- nextmv/cloud/status.py +95 -2
- nextmv/cloud/version.py +132 -4
- nextmv/deprecated.py +36 -2
- nextmv/input.py +298 -80
- nextmv/logger.py +71 -7
- nextmv/model.py +223 -56
- nextmv/options.py +281 -66
- nextmv/output.py +552 -159
- {nextmv-0.27.0.dist-info → nextmv-0.28.1.dist-info}/METADATA +24 -4
- nextmv-0.28.1.dist-info/RECORD +30 -0
- nextmv-0.27.0.dist-info/RECORD +0 -30
- {nextmv-0.27.0.dist-info → nextmv-0.28.1.dist-info}/WHEEL +0 -0
- {nextmv-0.27.0.dist-info → nextmv-0.28.1.dist-info}/licenses/LICENSE +0 -0
nextmv/model.py
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Model module for creating and saving decision models in Nextmv Cloud.
|
|
3
|
+
|
|
4
|
+
This module provides the base classes and functionality for creating decision models
|
|
5
|
+
that can be deployed and run in Nextmv Cloud. The main components are:
|
|
6
|
+
|
|
7
|
+
Classes
|
|
8
|
+
-------
|
|
9
|
+
Model
|
|
10
|
+
Base class for defining decision models.
|
|
11
|
+
ModelConfiguration
|
|
12
|
+
Configuration for packaging and deploying models.
|
|
13
|
+
|
|
14
|
+
Models defined using this module can be packaged with their dependencies and
|
|
15
|
+
deployed to Nextmv Cloud for execution.
|
|
16
|
+
"""
|
|
17
|
+
|
|
1
18
|
import logging
|
|
2
19
|
import os
|
|
3
20
|
import shutil
|
|
@@ -13,10 +30,44 @@ from nextmv.output import Output
|
|
|
13
30
|
# The following block of code is used to suppress warnings from mlflow. We
|
|
14
31
|
# suppress these warnings because they are not relevant to the user, and they
|
|
15
32
|
# are not actionable.
|
|
16
|
-
original_showwarning = warnings.showwarning
|
|
17
33
|
|
|
34
|
+
"""
|
|
35
|
+
Module-level function and variable to suppress warnings from mlflow.
|
|
36
|
+
"""
|
|
18
37
|
|
|
19
|
-
|
|
38
|
+
_original_showwarning = warnings.showwarning
|
|
39
|
+
"""Original showwarning function from the warnings module."""
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _custom_showwarning(message, category, filename, lineno, file=None, line=None):
|
|
43
|
+
"""
|
|
44
|
+
Custom warning handler that suppresses specific mlflow warnings.
|
|
45
|
+
|
|
46
|
+
This function filters out non-actionable warnings from the mlflow library
|
|
47
|
+
to keep the console output clean and relevant for the user.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
message : str
|
|
52
|
+
The warning message.
|
|
53
|
+
category : Warning
|
|
54
|
+
The warning category.
|
|
55
|
+
filename : str
|
|
56
|
+
The filename where the warning was raised.
|
|
57
|
+
lineno : int
|
|
58
|
+
The line number where the warning was raised.
|
|
59
|
+
file : file, optional
|
|
60
|
+
The file to write the warning to.
|
|
61
|
+
line : str, optional
|
|
62
|
+
The line of source code to be included in the warning message.
|
|
63
|
+
|
|
64
|
+
Returns
|
|
65
|
+
-------
|
|
66
|
+
None
|
|
67
|
+
If the warning matches certain patterns, the function returns early
|
|
68
|
+
without showing the warning. Otherwise, it delegates to the original
|
|
69
|
+
warning handler.
|
|
70
|
+
"""
|
|
20
71
|
# .../site-packages/mlflow/pyfunc/utils/data_validation.py:134: UserWarning:Add
|
|
21
72
|
# type hints to the `predict` method to enable data validation and automatic
|
|
22
73
|
# signature inference during model logging. Check
|
|
@@ -33,10 +84,10 @@ def custom_showwarning(message, category, filename, lineno, file=None, line=None
|
|
|
33
84
|
if "mlflow/pyfunc/__init__.py" in filename:
|
|
34
85
|
return
|
|
35
86
|
|
|
36
|
-
|
|
87
|
+
_original_showwarning(message, category, filename, lineno, file, line)
|
|
37
88
|
|
|
38
89
|
|
|
39
|
-
warnings.showwarning =
|
|
90
|
+
warnings.showwarning = _custom_showwarning
|
|
40
91
|
|
|
41
92
|
# When working with the `Model`, we expect to be working in a notebook
|
|
42
93
|
# environment, and not interact with the local filesystem a lot. We use the
|
|
@@ -53,23 +104,43 @@ _REQUIREMENTS_FILE = "model_requirements.txt"
|
|
|
53
104
|
# can run in Nextmv Cloud. This file is used as that entrypoint.
|
|
54
105
|
_ENTRYPOINT_FILE = "__entrypoint__.py"
|
|
55
106
|
|
|
107
|
+
|
|
108
|
+
# Required mlflow dependency version for model packaging.
|
|
56
109
|
_MLFLOW_DEPENDENCY = "mlflow>=2.18.0"
|
|
57
110
|
|
|
58
111
|
|
|
59
112
|
@dataclass
|
|
60
113
|
class ModelConfiguration:
|
|
61
114
|
"""
|
|
62
|
-
|
|
63
|
-
model. It is used to define how a Python model is encoded and loaded.
|
|
115
|
+
Configuration class for Nextmv models.
|
|
64
116
|
|
|
65
|
-
|
|
117
|
+
You can import the `ModelConfiguration` class directly from `nextmv`:
|
|
66
118
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
119
|
+
```python
|
|
120
|
+
from nextmv import ModelConfiguration
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
This class holds the configuration for a model, defining how a Python model
|
|
124
|
+
is encoded and loaded for use in Nextmv Cloud.
|
|
125
|
+
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
name : str
|
|
129
|
+
A personalized name for the model. This is required.
|
|
130
|
+
requirements : list[str], optional
|
|
131
|
+
A list of Python dependencies that the decision model requires,
|
|
132
|
+
formatted as they would appear in a requirements.txt file.
|
|
133
|
+
options : Options, optional
|
|
134
|
+
Options that the decision model requires.
|
|
135
|
+
|
|
136
|
+
Examples
|
|
137
|
+
--------
|
|
138
|
+
>>> from nextmv import ModelConfiguration, Options
|
|
139
|
+
>>> config = ModelConfiguration(
|
|
140
|
+
... name="my_routing_model",
|
|
141
|
+
... requirements=["nextroute>=1.0.0"],
|
|
142
|
+
... options=Options({"max_time": 60})
|
|
143
|
+
... )
|
|
73
144
|
"""
|
|
74
145
|
|
|
75
146
|
name: str
|
|
@@ -83,41 +154,50 @@ class ModelConfiguration:
|
|
|
83
154
|
|
|
84
155
|
class Model:
|
|
85
156
|
"""
|
|
86
|
-
|
|
87
|
-
Cloud. You must create a subclass of this class and implement the `solve`
|
|
88
|
-
method. The `solve` method is the main entry point of your model and should
|
|
89
|
-
return an output with a solution (decision).
|
|
157
|
+
Base class for defining decision models that run in Nextmv Cloud.
|
|
90
158
|
|
|
91
|
-
|
|
92
|
-
-------
|
|
93
|
-
```python
|
|
94
|
-
import nextroute
|
|
95
|
-
|
|
96
|
-
import nextmv
|
|
159
|
+
You can import the `Model` class directly from `nextmv`:
|
|
97
160
|
|
|
161
|
+
```python
|
|
162
|
+
from nextmv import Model
|
|
163
|
+
```
|
|
98
164
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
def solve(self, input: nextmv.Input) -> nextmv.Output:
|
|
103
|
-
nextroute_input = nextroute.schema.Input.from_dict(input.data)
|
|
104
|
-
nextroute_options = nextroute.Options.extract_from_dict(input.options.to_dict())
|
|
105
|
-
nextroute_output = nextroute.solve(nextroute_input, nextroute_options)
|
|
165
|
+
This class serves as a foundation for creating decision models that can be
|
|
166
|
+
deployed to Nextmv Cloud. Subclasses must implement the `solve` method,
|
|
167
|
+
which is the main entry point for processing inputs and producing decisions.
|
|
106
168
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
169
|
+
Methods
|
|
170
|
+
-------
|
|
171
|
+
solve(input)
|
|
172
|
+
Process input data and produce a decision output.
|
|
173
|
+
save(model_dir, configuration)
|
|
174
|
+
Save the model to the filesystem for deployment.
|
|
175
|
+
|
|
176
|
+
Examples
|
|
177
|
+
--------
|
|
178
|
+
>>> import nextroute
|
|
179
|
+
>>> import nextmv
|
|
180
|
+
>>>
|
|
181
|
+
>>> class DecisionModel(nextmv.Model):
|
|
182
|
+
... def solve(self, input: nextmv.Input) -> nextmv.Output:
|
|
183
|
+
... nextroute_input = nextroute.schema.Input.from_dict(input.data)
|
|
184
|
+
... nextroute_options = nextroute.Options.extract_from_dict(input.options.to_dict())
|
|
185
|
+
... nextroute_output = nextroute.solve(nextroute_input, nextroute_options)
|
|
186
|
+
...
|
|
187
|
+
... return nextmv.Output(
|
|
188
|
+
... options=input.options,
|
|
189
|
+
... solution=nextroute_output.solutions[0].to_dict(),
|
|
190
|
+
... statistics=nextroute_output.statistics.to_dict(),
|
|
191
|
+
... )
|
|
113
192
|
"""
|
|
114
193
|
|
|
115
194
|
def solve(self, input: Input) -> Output:
|
|
116
195
|
"""
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
196
|
+
Process input data and produce a decision output.
|
|
197
|
+
|
|
198
|
+
This is the main entry point of your model that you must implement in
|
|
199
|
+
subclasses. It receives input data and should process it to produce an
|
|
200
|
+
output containing the solution to the decision problem.
|
|
121
201
|
|
|
122
202
|
Parameters
|
|
123
203
|
----------
|
|
@@ -129,23 +209,63 @@ class Model:
|
|
|
129
209
|
Output
|
|
130
210
|
The output of the model, which is the solution to the decision
|
|
131
211
|
model/problem.
|
|
212
|
+
|
|
213
|
+
Raises
|
|
214
|
+
------
|
|
215
|
+
NotImplementedError
|
|
216
|
+
When called on the base Model class, as this method must be
|
|
217
|
+
implemented by subclasses.
|
|
218
|
+
|
|
219
|
+
Examples
|
|
220
|
+
--------
|
|
221
|
+
>>> def solve(self, input: Input) -> Output:
|
|
222
|
+
... # Process input data
|
|
223
|
+
... result = self._process_data(input.data)
|
|
224
|
+
...
|
|
225
|
+
... # Return formatted output
|
|
226
|
+
... return Output(
|
|
227
|
+
... options=input.options,
|
|
228
|
+
... solution=result,
|
|
229
|
+
... statistics={"processing_time": 0.5}
|
|
230
|
+
... )
|
|
132
231
|
"""
|
|
133
232
|
|
|
134
233
|
raise NotImplementedError
|
|
135
234
|
|
|
136
235
|
def save(model_self, model_dir: str, configuration: ModelConfiguration) -> None:
|
|
137
236
|
"""
|
|
138
|
-
Save the model to the local filesystem
|
|
139
|
-
|
|
140
|
-
|
|
237
|
+
Save the model to the local filesystem for deployment.
|
|
238
|
+
|
|
239
|
+
This method packages the model according to the provided configuration,
|
|
240
|
+
creating all necessary files and dependencies for deployment to Nextmv
|
|
241
|
+
Cloud.
|
|
141
242
|
|
|
142
243
|
Parameters
|
|
143
244
|
----------
|
|
144
|
-
|
|
245
|
+
model_dir : str
|
|
145
246
|
The directory where the model will be saved.
|
|
146
247
|
configuration : ModelConfiguration
|
|
147
248
|
The configuration of the model, which defines how the model is
|
|
148
249
|
saved and loaded.
|
|
250
|
+
|
|
251
|
+
Raises
|
|
252
|
+
------
|
|
253
|
+
ImportError
|
|
254
|
+
If mlflow is not installed, which is required for model packaging.
|
|
255
|
+
|
|
256
|
+
Notes
|
|
257
|
+
-----
|
|
258
|
+
This method uses mlflow for model packaging, creating the necessary
|
|
259
|
+
files and directory structure for deployment.
|
|
260
|
+
|
|
261
|
+
Examples
|
|
262
|
+
--------
|
|
263
|
+
>>> model = MyDecisionModel()
|
|
264
|
+
>>> config = ModelConfiguration(
|
|
265
|
+
... name="routing_model",
|
|
266
|
+
... requirements=["pandas", "numpy"]
|
|
267
|
+
... )
|
|
268
|
+
>>> model.save("/tmp/my_model", config)
|
|
149
269
|
"""
|
|
150
270
|
|
|
151
271
|
# mlflow is a big package. We don't want to make it a dependency of
|
|
@@ -165,12 +285,15 @@ class Model:
|
|
|
165
285
|
|
|
166
286
|
class MLFlowModel(PythonModel):
|
|
167
287
|
"""
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
class
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
288
|
+
Transient class to translate a Nextmv Decision Model into an MLflow PythonModel.
|
|
289
|
+
|
|
290
|
+
This class complies with the MLflow inference API, implementing a `predict`
|
|
291
|
+
method that calls the user-defined `solve` method of the Nextmv Decision Model.
|
|
292
|
+
|
|
293
|
+
Methods
|
|
294
|
+
-------
|
|
295
|
+
predict(context, model_input, params)
|
|
296
|
+
MLflow-compliant predict method that delegates to the Nextmv model's solve method.
|
|
174
297
|
"""
|
|
175
298
|
|
|
176
299
|
def predict(
|
|
@@ -180,11 +303,28 @@ class Model:
|
|
|
180
303
|
params: Optional[dict[str, Any]] = None,
|
|
181
304
|
) -> Any:
|
|
182
305
|
"""
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
306
|
+
MLflow-compliant prediction method that calls the Nextmv model's solve method.
|
|
307
|
+
|
|
308
|
+
This method enables compatibility with MLflow's python_function model flavor.
|
|
309
|
+
|
|
310
|
+
Parameters
|
|
311
|
+
----------
|
|
312
|
+
context : mlflow.pyfunc.PythonModelContext
|
|
313
|
+
The MLflow model context.
|
|
314
|
+
model_input : Any
|
|
315
|
+
The input data for prediction, passed to the solve method.
|
|
316
|
+
params : Optional[dict[str, Any]], optional
|
|
317
|
+
Additional parameters for prediction.
|
|
318
|
+
|
|
319
|
+
Returns
|
|
320
|
+
-------
|
|
321
|
+
Any
|
|
322
|
+
The result from the Nextmv model's solve method.
|
|
323
|
+
|
|
324
|
+
Notes
|
|
325
|
+
-----
|
|
326
|
+
This method should not be used or overridden directly. Instead,
|
|
327
|
+
implement the `solve` method in your Nextmv Model subclass.
|
|
188
328
|
"""
|
|
189
329
|
|
|
190
330
|
return model_self.solve(model_input)
|
|
@@ -231,7 +371,34 @@ def _cleanup_python_model(
|
|
|
231
371
|
model_configuration: Optional[ModelConfiguration] = None,
|
|
232
372
|
verbose: bool = False,
|
|
233
373
|
) -> None:
|
|
234
|
-
"""
|
|
374
|
+
"""
|
|
375
|
+
Clean up Python-specific model packaging artifacts.
|
|
376
|
+
|
|
377
|
+
This function removes temporary files and directories created during the
|
|
378
|
+
model packaging process.
|
|
379
|
+
|
|
380
|
+
Parameters
|
|
381
|
+
----------
|
|
382
|
+
model_dir : str
|
|
383
|
+
The directory where the model was saved.
|
|
384
|
+
model_configuration : Optional[ModelConfiguration], optional
|
|
385
|
+
The configuration of the model. If None, the function returns early.
|
|
386
|
+
verbose : bool, default=False
|
|
387
|
+
If True, log a message when cleanup is complete.
|
|
388
|
+
|
|
389
|
+
Returns
|
|
390
|
+
-------
|
|
391
|
+
None
|
|
392
|
+
This function does not return anything.
|
|
393
|
+
|
|
394
|
+
Notes
|
|
395
|
+
-----
|
|
396
|
+
Files and directories removed include:
|
|
397
|
+
- The model directory itself
|
|
398
|
+
- The mlruns directory created by MLflow
|
|
399
|
+
- The requirements file
|
|
400
|
+
- The main.py file
|
|
401
|
+
"""
|
|
235
402
|
|
|
236
403
|
if model_configuration is None:
|
|
237
404
|
return
|