nextmv 0.36.1.dev0__py3-none-any.whl → 0.37.1.dev0__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 CHANGED
@@ -1 +1 @@
1
- __version__ = "v0.36.1-dev.0"
1
+ __version__ = "v0.37.1.dev.0"
nextmv/cloud/__init__.py CHANGED
@@ -74,6 +74,10 @@ from .input_set import InputSet as InputSet
74
74
  from .input_set import ManagedInput as ManagedInput
75
75
  from .instance import Instance as Instance
76
76
  from .instance import InstanceConfiguration as InstanceConfiguration
77
+ from .integration import Integration as Integration
78
+ from .integration import IntegrationProvider as IntegrationProvider
79
+ from .integration import IntegrationType as IntegrationType
80
+ from .integration import list_integrations as list_integrations
77
81
  from .scenario import Scenario as Scenario
78
82
  from .scenario import ScenarioConfiguration as ScenarioConfiguration
79
83
  from .scenario import ScenarioInput as ScenarioInput
@@ -3215,7 +3215,7 @@ class Application:
3215
3215
  name: str | None = None,
3216
3216
  version_id: str | None = None,
3217
3217
  description: str | None = None,
3218
- configuration: InstanceConfiguration | None = None,
3218
+ configuration: InstanceConfiguration | dict[str, Any] | None = None,
3219
3219
  ) -> Instance:
3220
3220
  """
3221
3221
  Update an instance.
@@ -3230,7 +3230,7 @@ class Application:
3230
3230
  Optional ID of the version to associate the instance with.
3231
3231
  description : Optional[str], default=None
3232
3232
  Optional description of the instance.
3233
- configuration : Optional[InstanceConfiguration], default=None
3233
+ configuration : Optional[InstanceConfiguration | dict[str, Any]], default=None
3234
3234
  Optional configuration to use for the instance.
3235
3235
 
3236
3236
  Returns
@@ -3247,13 +3247,7 @@ class Application:
3247
3247
  # Get the instance as it currently exsits.
3248
3248
  instance = self.instance(id)
3249
3249
  instance_dict = instance.to_dict()
3250
-
3251
- payload = {
3252
- "name": instance_dict["name"],
3253
- "version_id": instance_dict["version_id"],
3254
- "description": instance_dict["description"],
3255
- "configuration": instance_dict["configuration"],
3256
- }
3250
+ payload = instance_dict
3257
3251
 
3258
3252
  if name is not None:
3259
3253
  payload["name"] = name
@@ -3262,7 +3256,14 @@ class Application:
3262
3256
  if description is not None:
3263
3257
  payload["description"] = description
3264
3258
  if configuration is not None:
3265
- payload["configuration"] = configuration.to_dict()
3259
+ if isinstance(configuration, dict):
3260
+ config_dict = configuration
3261
+ elif isinstance(configuration, InstanceConfiguration):
3262
+ config_dict = configuration.to_dict()
3263
+ else:
3264
+ raise TypeError("configuration must be either a dict or InstanceConfiguration object")
3265
+
3266
+ payload["configuration"] = config_dict
3266
3267
 
3267
3268
  response = self.client.request(
3268
3269
  method="PUT",
@@ -3303,11 +3304,7 @@ class Application:
3303
3304
 
3304
3305
  managed_input = self.managed_input(managed_input_id)
3305
3306
  managed_input_dict = managed_input.to_dict()
3306
-
3307
- payload = {
3308
- "name": managed_input_dict["name"],
3309
- "description": managed_input_dict["description"],
3310
- }
3307
+ payload = managed_input_dict
3311
3308
 
3312
3309
  if name is not None:
3313
3310
  payload["name"] = name
@@ -3376,7 +3373,7 @@ class Application:
3376
3373
  secrets_collection_id: str,
3377
3374
  name: str | None = None,
3378
3375
  description: str | None = None,
3379
- secrets: list[Secret] | None = None,
3376
+ secrets: list[Secret | dict[str, Any]] | None = None,
3380
3377
  ) -> SecretsCollectionSummary:
3381
3378
  """
3382
3379
  Update a secrets collection.
@@ -3393,7 +3390,7 @@ class Application:
3393
3390
  Optional new name for the secrets collection.
3394
3391
  description : Optional[str], default=None
3395
3392
  Optional new description for the secrets collection.
3396
- secrets : Optional[list[Secret]], default=None
3393
+ secrets : Optional[list[Secret | dict[str, Any]]], default=None
3397
3394
  Optional list of secrets to update. Each secret should be an
3398
3395
  instance of the Secret class containing a key and value.
3399
3396
 
@@ -3429,19 +3426,23 @@ class Application:
3429
3426
 
3430
3427
  collection = self.secrets_collection(secrets_collection_id)
3431
3428
  collection_dict = collection.to_dict()
3432
-
3433
- payload = {
3434
- "name": collection_dict["name"],
3435
- "description": collection_dict["description"],
3436
- "secrets": collection_dict["secrets"],
3437
- }
3429
+ payload = collection_dict
3438
3430
 
3439
3431
  if name is not None:
3440
3432
  payload["name"] = name
3441
3433
  if description is not None:
3442
3434
  payload["description"] = description
3443
3435
  if secrets is not None and len(secrets) > 0:
3444
- payload["secrets"] = [secret.to_dict() for secret in secrets]
3436
+ secrets_dicts = []
3437
+ for ix, secret in enumerate(secrets):
3438
+ if isinstance(secret, dict):
3439
+ secrets_dicts.append(secret)
3440
+ elif isinstance(secret, Secret):
3441
+ secrets_dicts.append(secret.to_dict())
3442
+ else:
3443
+ raise ValueError(f"secret at index {ix} must be either a Secret or dict object")
3444
+
3445
+ payload["secrets"] = secrets_dicts
3445
3446
 
3446
3447
  response = self.client.request(
3447
3448
  method="PUT",
@@ -0,0 +1,533 @@
1
+ """
2
+ Integration module for interacting with Nextmv Cloud integrations.
3
+
4
+ This module provides functionality to interact with integrations in Nextmv
5
+ Cloud, including integration management.
6
+
7
+ Classes
8
+ -------
9
+ IntegrationType
10
+ Enum representing the type of an integration.
11
+ IntegrationProvider
12
+ Enum representing the provider of an integration.
13
+ Integration
14
+ Class representing an integration in Nextmv Cloud.
15
+
16
+ Functions
17
+ ---------
18
+ list_integrations
19
+ Function to list all integrations in Nextmv Cloud.
20
+ """
21
+
22
+ from datetime import datetime
23
+ from enum import Enum
24
+ from typing import Any
25
+
26
+ from pydantic import AliasChoices, Field
27
+
28
+ from nextmv.base_model import BaseModel
29
+ from nextmv.cloud.client import Client
30
+ from nextmv.manifest import ManifestType
31
+ from nextmv.safe import safe_id
32
+
33
+
34
+ class IntegrationType(str, Enum):
35
+ """
36
+ The type of an integration.
37
+
38
+ You can import the `IntegrationType` class directly from `cloud`:
39
+
40
+ ```python
41
+ from nextmv.cloud import IntegrationType
42
+ ```
43
+
44
+ Attributes
45
+ ----------
46
+ RUNTIME : str
47
+ Indicates a runtime integration.
48
+ DATA : str
49
+ Indicates a data integration.
50
+ """
51
+
52
+ RUNTIME = "runtime"
53
+ """Indicates a runtime integration."""
54
+ DATA = "data"
55
+ """Indicates a data integration."""
56
+
57
+
58
+ class IntegrationProvider(str, Enum):
59
+ """
60
+ The provider of an integration.
61
+
62
+ You can import the `IntegrationProvider` class directly from `cloud`:
63
+
64
+ ```python
65
+ from nextmv.cloud import IntegrationProvider
66
+ ```
67
+
68
+ Attributes
69
+ ----------
70
+ DBX : str
71
+ Indicates a Databricks integration.
72
+ UNKNOWN : str
73
+ Indicates an unknown integration provider.
74
+ """
75
+
76
+ DBX = "dbx"
77
+ """Indicates a Databricks integration."""
78
+ UNKNOWN = "unknown"
79
+ """Indicates an unknown integration provider."""
80
+
81
+
82
+ class Integration(BaseModel):
83
+ """
84
+ Represents an integration in Nextmv Cloud. An integration allows Nextmv
85
+ Cloud to communicate with external systems or services.
86
+
87
+ You can import the `Integration` class directly from `cloud`:
88
+
89
+ ```python
90
+ from nextmv.cloud import Integration
91
+ ```
92
+
93
+ You can use the `Integration.get` class method to retrieve an existing
94
+ integration from Nextmv Cloud, to ensure that all fields are properly
95
+ populated.
96
+
97
+ Parameters
98
+ ----------
99
+ integration_id : str
100
+ The unique identifier of the integration.
101
+ client : Client
102
+ Client to use for interacting with the Nextmv Cloud API.
103
+ name : str, optional
104
+ The name of the integration.
105
+ description : str, optional
106
+ An optional description of the integration.
107
+ is_global : bool, optional
108
+ Indicates whether the integration is global (available to all
109
+ applications in the account).
110
+ application_ids : list[str], optional
111
+ List of application IDs that have access to this integration.
112
+ integration_type : IntegrationType, optional
113
+ The type of the integration (runtime or data).
114
+ exec_types : list[ManifestType], optional
115
+ List of execution types supported by the integration.
116
+ provider : IntegrationProvider, optional
117
+ The provider of the integration.
118
+ provider_config : dict[str, Any], optional
119
+ Configuration specific to the integration provider.
120
+ created_at : datetime, optional
121
+ The timestamp when the integration was created.
122
+ updated_at : datetime, optional
123
+ The timestamp when the integration was last updated.
124
+ """
125
+
126
+ integration_id: str = Field(
127
+ serialization_alias="id",
128
+ validation_alias=AliasChoices("id", "integration_id"),
129
+ )
130
+ """The unique identifier of the integration."""
131
+ client: Client = Field(exclude=True)
132
+ """Client to use for interacting with the Nextmv Cloud API."""
133
+
134
+ name: str | None = None
135
+ """The name of the integration."""
136
+ description: str | None = None
137
+ """An optional description of the integration."""
138
+ is_global: bool = Field(
139
+ serialization_alias="global",
140
+ validation_alias=AliasChoices("global", "is_global"),
141
+ default=False,
142
+ )
143
+ """
144
+ Indicates whether the integration is global (available to all
145
+ applications in the account).
146
+ """
147
+ application_ids: list[str] | None = None
148
+ """
149
+ List of application IDs that have access to this integration.
150
+ """
151
+ integration_type: IntegrationType | None = Field(
152
+ serialization_alias="type",
153
+ validation_alias=AliasChoices("type", "integration_type"),
154
+ default=None,
155
+ )
156
+ """The type of the integration (runtime or data)."""
157
+ exec_types: list[ManifestType] | None = None
158
+ """List of execution types supported by the integration."""
159
+ provider: IntegrationProvider | None = None
160
+ """The provider of the integration."""
161
+ provider_config: dict[str, Any] | None = None
162
+ """Configuration specific to the integration provider."""
163
+ created_at: datetime | None = None
164
+ """The timestamp when the integration was created."""
165
+ updated_at: datetime | None = None
166
+ """The timestamp when the integration was last updated."""
167
+ endpoint: str = Field(
168
+ exclude=True,
169
+ default="v1/integrations/{id}",
170
+ )
171
+ """Base endpoint for the integration."""
172
+
173
+ def model_post_init(self, __context) -> None:
174
+ """
175
+ Validations done after model initialization.
176
+ """
177
+
178
+ self.endpoint = self.endpoint.format(id=self.integration_id)
179
+
180
+ @classmethod
181
+ def get(cls, client: Client, integration_id: str) -> "Integration":
182
+ """
183
+ Retrieve an existing integration from Nextmv Cloud.
184
+
185
+ This method should be used for validating that the integration exists,
186
+ and not rely simply on instantiating the `Integration` class. Using
187
+ this method ensures that all the fields of the `Integration` class are
188
+ properly populated.
189
+
190
+ Parameters
191
+ ----------
192
+ client : Client
193
+ Client to use for interacting with the Nextmv Cloud API.
194
+ integration_id : str
195
+ The unique identifier of the integration to retrieve.
196
+
197
+ Returns
198
+ -------
199
+ Integration
200
+ The retrieved integration instance.
201
+
202
+ Raises
203
+ ------
204
+ requests.HTTPError
205
+ If the response status code is not 2xx.
206
+
207
+ Examples
208
+ --------
209
+ >>> from nextmv.cloud import Client, Integration
210
+ >>> client = Client(api_key="your_api_key")
211
+ >>> integration = Integration.get(client=client, integration_id="your_integration_id")
212
+ >>> print(integration.to_dict())
213
+ """
214
+
215
+ response = client.request(
216
+ method="GET",
217
+ endpoint=f"v1/integrations/{integration_id}",
218
+ )
219
+ response_dict = response.json()
220
+ response_dict["client"] = client
221
+
222
+ return cls.from_dict(response_dict)
223
+
224
+ @classmethod
225
+ def new( # noqa: C901
226
+ cls,
227
+ client: Client,
228
+ name: str,
229
+ integration_type: IntegrationType | str,
230
+ exec_types: list[ManifestType | str],
231
+ provider: IntegrationProvider | str,
232
+ provider_config: dict[str, Any],
233
+ integration_id: str | None = None,
234
+ description: str | None = None,
235
+ is_global: bool = False,
236
+ application_ids: list[str] | None = None,
237
+ exist_ok: bool = False,
238
+ ) -> "Integration":
239
+ """
240
+ Create a new integration directly in Nextmv Cloud.
241
+
242
+ Parameters
243
+ ----------
244
+ client : Client
245
+ Client to use for interacting with the Nextmv Cloud API.
246
+ name : str
247
+ The name of the integration.
248
+ integration_type : IntegrationType | str
249
+ The type of the integration. Please refer to the `IntegrationType`
250
+ enum for possible values.
251
+ exec_types : list[ManifestType | str]
252
+ List of execution types supported by the integration. Please refer
253
+ to the `ManifestType` enum for possible values.
254
+ provider : IntegrationProvider | str
255
+ The provider of the integration. Please refer to the
256
+ `IntegrationProvider` enum for possible values.
257
+ provider_config : dict[str, Any]
258
+ Configuration specific to the integration provider.
259
+ integration_id : str, optional
260
+ The unique identifier of the integration. If not provided,
261
+ it will be generated automatically.
262
+ description : str, optional
263
+ An optional description of the integration.
264
+ is_global : bool, optional, default=False
265
+ Indicates whether the integration is global (available to all
266
+ applications in the account). Default is False.
267
+ application_ids : list[str], optional
268
+ List of application IDs that have access to this integration.
269
+ exist_ok : bool, default=False
270
+ If True and an integration with the same ID already exists,
271
+ return the existing integration instead of creating a new one.
272
+
273
+ Returns
274
+ -------
275
+ Integration
276
+ The created integration instance.
277
+
278
+ Raises
279
+ ------
280
+ requests.HTTPError
281
+ If the response status code is not 2xx.
282
+ ValueError
283
+ If both `is_global` is True and `application_ids` is provided.
284
+
285
+ Examples
286
+ --------
287
+ >>> from nextmv.cloud import Client, Integration, IntegrationType, IntegrationProvider, ManifestType
288
+ >>> client = Client(api_key="your_api_key")
289
+ >>> integration = Integration.new(
290
+ ... client=client,
291
+ ... name="my_integration",
292
+ ... integration_type=IntegrationType.RUNTIME,
293
+ ... exec_types=[ManifestType.PYTHON],
294
+ ... provider=IntegrationProvider.DBX,
295
+ ... provider_config={"config_key": "config_value"},
296
+ ... )
297
+ >>> print(integration.to_dict())
298
+ """
299
+
300
+ if is_global and application_ids is not None:
301
+ raise ValueError("An integration cannot be global and have specific application IDs.")
302
+ elif not is_global and application_ids is None:
303
+ raise ValueError("A non-global integration must have specific application IDs.")
304
+
305
+ if integration_id is None:
306
+ integration_id = safe_id("integration")
307
+
308
+ if exist_ok:
309
+ try:
310
+ integration = cls.get(client=client, integration_id=integration_id)
311
+ return integration
312
+ except Exception:
313
+ pass
314
+
315
+ if not isinstance(integration_type, IntegrationType):
316
+ integration_type = IntegrationType(integration_type)
317
+
318
+ if not all(isinstance(exec_type, ManifestType) for exec_type in exec_types):
319
+ exec_types = [ManifestType(exec_type) for exec_type in exec_types]
320
+
321
+ if not isinstance(provider, IntegrationProvider):
322
+ provider = IntegrationProvider(provider)
323
+
324
+ payload = {
325
+ "id": integration_id,
326
+ "name": name,
327
+ "global": is_global,
328
+ "type": integration_type.value,
329
+ "exec_types": [exec_type.value for exec_type in exec_types],
330
+ "provider": provider.value,
331
+ "provider_config": provider_config,
332
+ }
333
+
334
+ if description is not None:
335
+ payload["description"] = description
336
+
337
+ if application_ids is not None:
338
+ payload["application_ids"] = application_ids
339
+
340
+ response = client.request(
341
+ method="POST",
342
+ endpoint="v1/integrations",
343
+ payload=payload,
344
+ )
345
+ response_dict = response.json()
346
+ response_dict["client"] = client
347
+ integration = cls.from_dict(response_dict)
348
+
349
+ return integration
350
+
351
+ def delete(self) -> None:
352
+ """
353
+ Deletes the integration from Nextmv Cloud.
354
+
355
+ Raises
356
+ ------
357
+ requests.HTTPError
358
+ If the response status code is not 2xx.
359
+
360
+ Examples
361
+ --------
362
+ >>> from nextmv.cloud import Client, Integration
363
+ >>> client = Client(api_key="your_api_key")
364
+ >>> integration = Integration.get(client=client, integration_id="your_integration_id")
365
+ >>> integration.delete()
366
+ """
367
+
368
+ _ = self.client.request(
369
+ method="DELETE",
370
+ endpoint=self.endpoint,
371
+ )
372
+
373
+ def update( # noqa: C901
374
+ self,
375
+ name: str | None = None,
376
+ integration_type: IntegrationType | str | None = None,
377
+ exec_types: list[ManifestType | str] | None = None,
378
+ provider: IntegrationProvider | str | None = None,
379
+ provider_config: dict[str, Any] | None = None,
380
+ description: str | None = None,
381
+ is_global: bool | None = None,
382
+ application_ids: list[str] | None = None,
383
+ ) -> "Integration":
384
+ """
385
+ Updates the integration in Nextmv Cloud.
386
+
387
+ Parameters
388
+ ----------
389
+ name : str, optional
390
+ The new name of the integration.
391
+ integration_type : IntegrationType | str, optional
392
+ The new type of the integration. Please refer to the `IntegrationType`
393
+ enum for possible values.
394
+ exec_types : list[ManifestType | str], optional
395
+ New list of execution types supported by the integration. Please refer
396
+ to the `ManifestType` enum for possible values.
397
+ provider : IntegrationProvider | str, optional
398
+ The new provider of the integration. Please refer to the
399
+ `IntegrationProvider` enum for possible values.
400
+ provider_config : dict[str, Any], optional
401
+ New configuration specific to the integration provider.
402
+ description : str, optional
403
+ The new description of the integration.
404
+ is_global : bool, optional
405
+ Indicates whether the integration is global (available to all
406
+ applications in the account). If not provided, the current value
407
+ is preserved.
408
+ application_ids : list[str], optional
409
+ New list of application IDs that have access to this integration.
410
+
411
+ Returns
412
+ -------
413
+ Integration
414
+ The updated integration instance.
415
+
416
+ Raises
417
+ ------
418
+ requests.HTTPError
419
+ If the response status code is not 2xx.
420
+
421
+ Examples
422
+ --------
423
+ >>> from nextmv.cloud import Client, Integration
424
+ >>> client = Client(api_key="your_api_key")
425
+ >>> integration = Integration.get(client=client, integration_id="your_integration_id")
426
+ >>> updated_integration = integration.update(name="new_name")
427
+ >>> print(updated_integration.to_dict())
428
+ """
429
+
430
+ integration = self.get(client=self.client, integration_id=self.integration_id)
431
+ integration_dict = integration.to_dict()
432
+ payload = integration_dict
433
+
434
+ if name is not None:
435
+ payload["name"] = name
436
+
437
+ if integration_type is not None:
438
+ if not isinstance(integration_type, IntegrationType):
439
+ integration_type = IntegrationType(integration_type)
440
+ payload["type"] = integration_type.value
441
+
442
+ if exec_types is not None:
443
+ if not all(isinstance(exec_type, ManifestType) for exec_type in exec_types):
444
+ exec_types = [ManifestType(exec_type) for exec_type in exec_types]
445
+ payload["exec_types"] = [exec_type.value for exec_type in exec_types]
446
+
447
+ if provider is not None:
448
+ if not isinstance(provider, IntegrationProvider):
449
+ provider = IntegrationProvider(provider)
450
+ payload["provider"] = provider.value
451
+
452
+ if provider_config is not None:
453
+ payload["provider_config"] = provider_config
454
+
455
+ if description is not None:
456
+ payload["description"] = description
457
+
458
+ if is_global is not None:
459
+ payload["global"] = is_global
460
+
461
+ if application_ids is not None:
462
+ payload["application_ids"] = application_ids
463
+
464
+ # Final validation: ensure invariants are met.
465
+ if payload["global"] is True and payload.get("application_ids"):
466
+ raise ValueError(
467
+ "An integration cannot be global and have application_ids. "
468
+ "To make an integration global, call update(is_global=True, application_ids=[])."
469
+ )
470
+ if payload["global"] is False and not payload.get("application_ids"):
471
+ raise ValueError(
472
+ "A non-global integration must have specific application IDs. "
473
+ "Provide application_ids with at least one ID, or set is_global=True."
474
+ )
475
+
476
+ response = self.client.request(
477
+ method="PUT",
478
+ endpoint=self.endpoint,
479
+ payload=payload,
480
+ )
481
+ response_dict = response.json()
482
+ response_dict["client"] = self.client
483
+ integration = self.from_dict(response_dict)
484
+
485
+ return integration
486
+
487
+
488
+ def list_integrations(client: Client) -> list[Integration]:
489
+ """
490
+ List all integrations in Nextmv Cloud for the given client.
491
+
492
+ You can import the `list_integrations` method directly from `cloud`:
493
+
494
+ ```python
495
+ from nextmv.cloud import list_integrations
496
+ ```
497
+
498
+ Parameters
499
+ ----------
500
+ client : Client
501
+ Client to use for interacting with the Nextmv Cloud API.
502
+
503
+ Returns
504
+ -------
505
+ list[Integration]
506
+ List of integrations.
507
+
508
+ Raises
509
+ ------
510
+ requests.HTTPError
511
+ If the response status code is not 2xx.
512
+
513
+ Examples
514
+ --------
515
+ >>> from nextmv.cloud import Client, list_integrations
516
+ >>> client = Client(api_key="your_api_key")
517
+ >>> integrations = list_integrations(client=client)
518
+ >>> for integration in integrations:
519
+ ... print(integration.to_dict())
520
+ """
521
+
522
+ response = client.request(
523
+ method="GET",
524
+ endpoint="v1/integrations",
525
+ )
526
+ response_dict = response.json()
527
+ integrations = []
528
+ for integration_data in response_dict.get("items", []):
529
+ integration_data["client"] = client
530
+ integration = Integration.from_dict(integration_data)
531
+ integrations.append(integration)
532
+
533
+ return integrations
nextmv/cloud/package.py CHANGED
@@ -330,12 +330,12 @@ def __install_dependencies( # noqa: C901 # complexity
330
330
  result = subprocess.run(
331
331
  command,
332
332
  cwd=app_dir,
333
+ stdout=subprocess.PIPE,
334
+ stderr=subprocess.STDOUT, # Merge stderr into stdout
333
335
  text=True,
334
- capture_output=True,
335
- check=True,
336
336
  )
337
337
  if result.returncode != 0:
338
- raise Exception(f"error installing dependencies: {result.stderr}")
338
+ raise Exception(f"error installing dependencies: {os.linesep}{result.stdout}")
339
339
 
340
340
 
341
341
  def __run_command(binary: str, dir: str, redirect_out_err: bool, *arguments: str) -> str:
@@ -1,4 +1,4 @@
1
- # Nextmv Application
1
+ # Nextmv application
2
2
 
3
3
  This is the basic structure of a Nextmv application.
4
4
 
nextmv/input.py CHANGED
@@ -998,7 +998,7 @@ def load_local(
998
998
 
999
999
  deprecated(
1000
1000
  name="load_local",
1001
- reason="`load_local` is deprecated, use `load` instead.",
1001
+ reason="`load_local` is deprecated, use `load` instead",
1002
1002
  )
1003
1003
 
1004
1004
  loader = LocalInputLoader()
@@ -7,7 +7,7 @@ including application management, running applications, and managing inputs.
7
7
  Classes
8
8
  -------
9
9
  Application
10
- Class for interacting with local Nextmv Applications.
10
+ Class for interacting with local Nextmv applications.
11
11
  """
12
12
 
13
13
  import json
nextmv/model.py CHANGED
@@ -284,7 +284,7 @@ class Model:
284
284
  import mlflow as mlflow
285
285
  except ImportError as e:
286
286
  raise ImportError(
287
- "mlflow is not installed. Please install optional dependencies with `pip install nextmv[all]`"
287
+ "mlflow is not installed. Please install optional dependencies with `pip install nextmv[notebook]`"
288
288
  ) from e
289
289
 
290
290
  finally:
nextmv/output.py CHANGED
@@ -1564,7 +1564,7 @@ def write_local(
1564
1564
 
1565
1565
  deprecated(
1566
1566
  name="write_local",
1567
- reason="`write_local` is deprecated, use `write` instead.",
1567
+ reason="`write_local` is deprecated, use `write` instead",
1568
1568
  )
1569
1569
 
1570
1570
  writer = LocalOutputWriter()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nextmv
3
- Version: 0.36.1.dev0
3
+ Version: 0.37.1.dev0
4
4
  Summary: The all-purpose Python SDK for Nextmv
5
5
  Project-URL: Homepage, https://www.nextmv.io
6
6
  Project-URL: Documentation, https://nextmv-py.docs.nextmv.io/en/latest/nextmv/
@@ -224,7 +224,6 @@ Requires-Dist: requests>=2.31.0
224
224
  Requires-Dist: urllib3>=2.1.0
225
225
  Provides-Extra: all
226
226
  Requires-Dist: folium>=0.20.0; extra == 'all'
227
- Requires-Dist: mlflow>=2.17.2; extra == 'all'
228
227
  Requires-Dist: plotly>=6.0.1; extra == 'all'
229
228
  Provides-Extra: dev
230
229
  Requires-Dist: build>=1.0.3; extra == 'dev'
@@ -240,6 +239,8 @@ Requires-Dist: requests>=2.31.0; extra == 'dev'
240
239
  Requires-Dist: ruff>=0.1.7; extra == 'dev'
241
240
  Requires-Dist: twine>=4.0.2; extra == 'dev'
242
241
  Requires-Dist: urllib3>=2.1.0; extra == 'dev'
242
+ Provides-Extra: notebook
243
+ Requires-Dist: mlflow>=2.19.0; extra == 'notebook'
243
244
  Description-Content-Type: text/markdown
244
245
 
245
246
  # Nextmv Python SDK
@@ -1,35 +1,36 @@
1
- nextmv/__about__.py,sha256=Nh_X8wPrV5KEw8PjC4o_QnZGRKpoVUE2ulupH9yXOqM,30
1
+ nextmv/__about__.py,sha256=jmJy02hqA-ohOlVowf2bmUsdVIOh5HJI-wmoH6yjah0,30
2
2
  nextmv/__entrypoint__.py,sha256=dA0iwwHtrq6Z9w9FxmxKLoBGLyhe7jWtUAU-Y3PEgHg,1094
3
3
  nextmv/__init__.py,sha256=mC-gAzCdoZJ0BOVe2fDzKNdBtbXzx8XOxHP_7DdPMdQ,3857
4
4
  nextmv/_serialization.py,sha256=jYitMS1MU8ldsmObT-K_8V8P2Wx69tnDiEHCCgPGun4,2834
5
5
  nextmv/base_model.py,sha256=kPFqE-c_3LcEy8fY0qDrJk_gbPYgSKtetRMby71oxE8,2298
6
6
  nextmv/deprecated.py,sha256=kEVfyQ-nT0v2ePXTNldjQG9uH5IlfQVy3L4tztIxwmU,1638
7
- nextmv/input.py,sha256=XRjINb438rnjvQwjCXVOJ0UPa-xTnZc9xBYt0NLhjGw,39970
7
+ nextmv/input.py,sha256=lFsjj92J7XRoGZwagFNeQxB5Ii_az7OHWIrk0Y0JuFE,39969
8
8
  nextmv/logger.py,sha256=kNIbu46MisrzYe4T0hNMpWfRTKKacDVvbtQcNys_c_E,2513
9
9
  nextmv/manifest.py,sha256=v9En9zMZVKZn6G_HThoKUZowMtZr5hxzwWiK9wkVHPU,49023
10
- nextmv/model.py,sha256=b323uAjr-eeChrIPLg4a8bnqOaoc12DQrQBnIPybd0k,14993
10
+ nextmv/model.py,sha256=9g-pAUg8E--CyUFU39J7e4MZcj0WrWtgIqfwGmoF7UA,14998
11
11
  nextmv/options.py,sha256=rfQV0F5_it-L27wjqrs902wr4Q7sgSN7dw5o0c5sdEg,37842
12
- nextmv/output.py,sha256=oqCnBvcYOZlvPSoX4trQ3EJR6GpE-4d0d7NDIq5hgL0,56008
12
+ nextmv/output.py,sha256=f7LZTs6vr8MEpzg2OFzZar0LOMVzglM3EpR7kYW-vrk,56007
13
13
  nextmv/polling.py,sha256=Mka7tChVR7Ws-Hg9W-Yzo7wthhVg-Qp-FK54E70Fzdw,9711
14
14
  nextmv/run.py,sha256=qeT3a0eqVHKvbQiFxmX_2epaj-rz2GyfpdZJ4ROFC4U,53135
15
15
  nextmv/safe.py,sha256=VAK4fGEurbLNji4Pg5Okga5XQSbI4aI9JJf95_68Z20,3867
16
16
  nextmv/status.py,sha256=SCDLhh2om3yeO5FxO0x-_RShQsZNXEpjHNdCGdb3VUI,2787
17
- nextmv/cloud/__init__.py,sha256=2wI72lhWq81BYv1OpS0OOTT5-3sivpX0H4z5ANPoLMc,5051
17
+ nextmv/cloud/__init__.py,sha256=4gV_w84BCenHlG5kTOWyGlg_I-kFxi4_XVb0K8No8vI,5295
18
18
  nextmv/cloud/acceptance_test.py,sha256=fZdp4O6pZrl7TaiUrTFPp7O4VJt-4R_W2yo4s8UAS5I,27691
19
19
  nextmv/cloud/account.py,sha256=jIdGNyI3l3dVh2PuriAwAOrEuWRM150WgzxcBMVBNRw,6058
20
- nextmv/cloud/application.py,sha256=29Tr7jWwa369ejkgFX3VXU_G3VK-2ATyL6Ma5tGXfAg,139592
20
+ nextmv/cloud/application.py,sha256=VU3F9M8VqPhUZL-6g6am-NFh_LQQ9j3gZCRAhY0qU_o,139892
21
21
  nextmv/cloud/batch_experiment.py,sha256=VmKgjBW6BpkH4loO0afMGNXrwJ5whhijQ99pm94vBto,10349
22
22
  nextmv/cloud/client.py,sha256=Yj4FE4GKsLHkYijAYXcotlyNfhAWANMuWetHXsYPg1M,18101
23
23
  nextmv/cloud/ensemble.py,sha256=_hKPjSLtuGH1xGG70ZBsmY_IL5XinZqVHHwBxtX9Omw,8570
24
24
  nextmv/cloud/input_set.py,sha256=wsLmMI1C7BslWDN5j1RnVUA8z54-Hq1eLG9bkzyqafo,4187
25
25
  nextmv/cloud/instance.py,sha256=kGhPefvN0AZBM4ZnrR8oknbqU_y4fk2isPY8hNaYew8,5015
26
- nextmv/cloud/package.py,sha256=f7ey70jv6gd4B6EdlhQKKM1nGtfMGgL8kmrTLPP2saY,15468
26
+ nextmv/cloud/integration.py,sha256=X26igTl3txL7yoIaP_pDDC2e8qVSYOsZADftaQISKbY,18105
27
+ nextmv/cloud/package.py,sha256=Wp2Rs2UWQjCJ3PIYVogswMhR6BLCbbi7SLcXqBJbLBk,15525
27
28
  nextmv/cloud/scenario.py,sha256=1_4PI9ehYaSonEe_l59cFhZNmqQ_brXXP6-mVq9i8a8,14183
28
29
  nextmv/cloud/secrets.py,sha256=fA5cX0jfTsPVZWV7433wzETGlXpWRLHGswuObx9e6FQ,6820
29
30
  nextmv/cloud/url.py,sha256=Fz70ywkWdCLmP21ZBmJwZi5kDbjpmsX_VlwVF_xQeHg,1836
30
31
  nextmv/cloud/version.py,sha256=5_S7_pWUVBFbvAArku20eK7S645GJcHtgE2OpXLdSzQ,5300
31
32
  nextmv/default_app/.gitignore,sha256=gsfnfXMYNt-YTroh5hAzauwBZoPDJ6D_fB17rMSnIko,8
32
- nextmv/default_app/README.md,sha256=OXJhlKeu4XYP4q9pf96eHHmsyoTvG7Vw2-t1DhAzufw,662
33
+ nextmv/default_app/README.md,sha256=hW3zWcYzxhYfof-pThaN1Fkx93GT8tTUVRhx15edBis,662
33
34
  nextmv/default_app/app.yaml,sha256=TKjKnuoK0SDpouB_AS7TQmE_8HZbQYjmwFvhzFL1xpc,382
34
35
  nextmv/default_app/input.json,sha256=zgvbKL3boB0WIU6-9mEU3ZWBddQ5cQ0vhgmDwDyz4hE,63
35
36
  nextmv/default_app/main.py,sha256=gG-1JIvKXPCkm4JV46PcXxsQTAefwPXQbdPxkSubhf0,888
@@ -37,13 +38,13 @@ nextmv/default_app/requirements.txt,sha256=wRE_HkYYWzCGnYZ2NuatHXul4gCHvU3iUAdsx
37
38
  nextmv/default_app/src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
39
  nextmv/default_app/src/visuals.py,sha256=WYK_YBnLmYo3TpVev1CpoNCuW5R7hk9QIkeCmvMn1Fs,1014
39
40
  nextmv/local/__init__.py,sha256=6BsoqlK4dw6X11_uKzz9gBPfxKpdiol2FYO8R3X73SE,116
40
- nextmv/local/application.py,sha256=RtqKR3yRI2GFn_RLyaRZMWZW30BuYllLdAY2OsPL7Xc,48245
41
+ nextmv/local/application.py,sha256=x5y87uCZCrq3mUBCVWLCzVUMVzCARdPNvkpqfggYe6A,48245
41
42
  nextmv/local/executor.py,sha256=1qoynUCB9UDgXhjXKds0OGc8McAtAsQHJ0-QVWTJrQs,36562
42
43
  nextmv/local/geojson_handler.py,sha256=7FavJdkUonop-yskjis0x3qFGB8A5wZyoBUblw-bVhw,12540
43
44
  nextmv/local/local.py,sha256=cp56UpI8h19Ob6Jvb_Ni0ceXH5Vv3ET_iPTDe6ftq3Y,2617
44
45
  nextmv/local/plotly_handler.py,sha256=bLb50e3AkVr_W-F6S7lXfeRdN60mG2jk3UElNmhoMWU,1930
45
46
  nextmv/local/runner.py,sha256=Fa-G4g5yaBgLeBfYU-ePs65Q3Ses_xYvXGhPtHpAkrU,8546
46
- nextmv-0.36.1.dev0.dist-info/METADATA,sha256=2iNvI67UmRYSzNIjHhoTqIA70n5vofqBaU8aHs8ODwI,15965
47
- nextmv-0.36.1.dev0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
48
- nextmv-0.36.1.dev0.dist-info/licenses/LICENSE,sha256=ZIbK-sSWA-OZprjNbmJAglYRtl5_K4l9UwAV3PGJAPc,11349
49
- nextmv-0.36.1.dev0.dist-info/RECORD,,
47
+ nextmv-0.37.1.dev0.dist-info/METADATA,sha256=G1Emcy0_HHozlRmqPaOR8MW6SXPbFA8du6i5ocvXOPg,15995
48
+ nextmv-0.37.1.dev0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
49
+ nextmv-0.37.1.dev0.dist-info/licenses/LICENSE,sha256=ZIbK-sSWA-OZprjNbmJAglYRtl5_K4l9UwAV3PGJAPc,11349
50
+ nextmv-0.37.1.dev0.dist-info/RECORD,,