nextmv 0.36.0__tar.gz → 0.36.1.dev0__tar.gz

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.
Files changed (88) hide show
  1. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/PKG-INFO +1 -1
  2. nextmv-0.36.1.dev0/nextmv/__about__.py +1 -0
  3. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/cloud/batch_experiment.py +1 -1
  4. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/cloud/instance.py +28 -0
  5. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/cloud/package.py +5 -0
  6. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/local/executor.py +2 -0
  7. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/manifest.py +2 -0
  8. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/run.py +25 -2
  9. nextmv-0.36.1.dev0/tests/cloud/test_instance.py +87 -0
  10. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/test_run.py +65 -0
  11. nextmv-0.36.0/nextmv/__about__.py +0 -1
  12. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/.gitignore +0 -0
  13. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/LICENSE +0 -0
  14. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/README.md +0 -0
  15. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/__entrypoint__.py +0 -0
  16. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/__init__.py +0 -0
  17. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/_serialization.py +0 -0
  18. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/base_model.py +0 -0
  19. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/cloud/__init__.py +0 -0
  20. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/cloud/acceptance_test.py +0 -0
  21. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/cloud/account.py +0 -0
  22. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/cloud/application.py +0 -0
  23. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/cloud/client.py +0 -0
  24. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/cloud/ensemble.py +0 -0
  25. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/cloud/input_set.py +0 -0
  26. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/cloud/scenario.py +0 -0
  27. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/cloud/secrets.py +0 -0
  28. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/cloud/url.py +0 -0
  29. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/cloud/version.py +0 -0
  30. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/default_app/.gitignore +0 -0
  31. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/default_app/README.md +0 -0
  32. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/default_app/app.yaml +0 -0
  33. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/default_app/input.json +0 -0
  34. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/default_app/main.py +0 -0
  35. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/default_app/requirements.txt +0 -0
  36. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/default_app/src/__init__.py +0 -0
  37. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/default_app/src/visuals.py +0 -0
  38. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/deprecated.py +0 -0
  39. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/input.py +0 -0
  40. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/local/__init__.py +0 -0
  41. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/local/application.py +0 -0
  42. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/local/geojson_handler.py +0 -0
  43. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/local/local.py +0 -0
  44. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/local/plotly_handler.py +0 -0
  45. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/local/runner.py +0 -0
  46. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/logger.py +0 -0
  47. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/model.py +0 -0
  48. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/options.py +0 -0
  49. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/output.py +0 -0
  50. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/polling.py +0 -0
  51. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/safe.py +0 -0
  52. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/nextmv/status.py +0 -0
  53. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/pyproject.toml +0 -0
  54. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/__init__.py +0 -0
  55. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/cloud/__init__.py +0 -0
  56. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/cloud/app.yaml +0 -0
  57. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/cloud/test_client.py +0 -0
  58. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/cloud/test_package.py +0 -0
  59. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/cloud/test_scenario.py +0 -0
  60. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/local/__init__.py +0 -0
  61. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/local/test_application.py +0 -0
  62. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/local/test_executor.py +0 -0
  63. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/local/test_runner.py +0 -0
  64. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/scripts/__init__.py +0 -0
  65. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/scripts/options1.py +0 -0
  66. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/scripts/options2.py +0 -0
  67. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/scripts/options3.py +0 -0
  68. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/scripts/options4.py +0 -0
  69. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/scripts/options5.py +0 -0
  70. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/scripts/options6.py +0 -0
  71. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/scripts/options7.py +0 -0
  72. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/scripts/options_deprecated.py +0 -0
  73. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/test_base_model.py +0 -0
  74. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/test_entrypoint/__init__.py +0 -0
  75. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/test_entrypoint/test_entrypoint.py +0 -0
  76. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/test_input.py +0 -0
  77. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/test_inputs/test_data.csv +0 -0
  78. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/test_inputs/test_data.json +0 -0
  79. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/test_inputs/test_data.txt +0 -0
  80. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/test_logger.py +0 -0
  81. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/test_manifest.py +0 -0
  82. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/test_model.py +0 -0
  83. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/test_options.py +0 -0
  84. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/test_output.py +0 -0
  85. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/test_polling.py +0 -0
  86. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/test_safe.py +0 -0
  87. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/test_serialization.py +0 -0
  88. {nextmv-0.36.0 → nextmv-0.36.1.dev0}/tests/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nextmv
3
- Version: 0.36.0
3
+ Version: 0.36.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/
@@ -0,0 +1 @@
1
+ __version__ = "v0.36.1-dev.0"
@@ -257,7 +257,7 @@ class BatchExperimentRun(BaseModel):
257
257
  repetition: int | None = None
258
258
  """Repetition number of the experiment."""
259
259
 
260
- def __post_init_post_parse__(self):
260
+ def model_post_init(self, __context) -> None:
261
261
  """
262
262
  Logic to run after the class is initialized.
263
263
 
@@ -15,6 +15,7 @@ Instance
15
15
  from datetime import datetime
16
16
 
17
17
  from nextmv.base_model import BaseModel
18
+ from nextmv.run import RunQueuing
18
19
 
19
20
 
20
21
  class InstanceConfiguration(BaseModel):
@@ -37,6 +38,10 @@ class InstanceConfiguration(BaseModel):
37
38
  Runtime options/parameters for the application.
38
39
  secrets_collection_id : str, optional
39
40
  ID of the secrets collection to use with this instance.
41
+ queuing : RunQueuing, optional
42
+ Queuing configuration for the instance.
43
+ integration_id : str, optional
44
+ ID of the integration to use for the instance.
40
45
 
41
46
  Examples
42
47
  --------
@@ -53,6 +58,29 @@ class InstanceConfiguration(BaseModel):
53
58
  """Options of the app that the instance uses."""
54
59
  secrets_collection_id: str | None = None
55
60
  """ID of the secrets collection that the instance uses."""
61
+ queuing: RunQueuing | None = None
62
+ """Queuing configuration for the instance."""
63
+ integration_id: str | None = None
64
+ """ID of the integration to use for the instance."""
65
+
66
+ def model_post_init(self, __context) -> None:
67
+ """
68
+ Validations done after parsing the model.
69
+
70
+ Raises
71
+ ------
72
+ ValueError
73
+ If execution_class is an empty string.
74
+ """
75
+
76
+ if self.integration_id is None or self.integration_id == "":
77
+ return
78
+
79
+ integration_val = "integration"
80
+ if self.execution_class is not None and self.execution_class != "" and self.execution_class != integration_val:
81
+ raise ValueError(f"When integration_id is set, execution_class must be `{integration_val}` or None.")
82
+
83
+ self.execution_class = integration_val
56
84
 
57
85
 
58
86
  class Instance(BaseModel):
@@ -16,6 +16,7 @@ from nextmv.model import Model, ModelConfiguration, _cleanup_python_model
16
16
  _MANDATORY_FILES_PER_TYPE = {
17
17
  ManifestType.PYTHON: ["main.py"],
18
18
  ManifestType.GO: ["main"],
19
+ ManifestType.BINARY: ["main"],
19
20
  ManifestType.JAVA: ["main.jar"],
20
21
  }
21
22
 
@@ -277,7 +278,9 @@ def __install_dependencies( # noqa: C901 # complexity
277
278
  "--platform=manylinux2014_aarch64",
278
279
  "--platform=manylinux_2_17_aarch64",
279
280
  "--platform=manylinux_2_24_aarch64",
281
+ "--platform=manylinux_2_26_aarch64",
280
282
  "--platform=manylinux_2_28_aarch64",
283
+ "--platform=manylinux_2_34_aarch64",
281
284
  "--platform=linux_aarch64",
282
285
  ]
283
286
  )
@@ -287,7 +290,9 @@ def __install_dependencies( # noqa: C901 # complexity
287
290
  "--platform=manylinux2014_x86_64",
288
291
  "--platform=manylinux_2_17_x86_64",
289
292
  "--platform=manylinux_2_24_x86_64",
293
+ "--platform=manylinux_2_26_x86_64",
290
294
  "--platform=manylinux_2_28_x86_64",
295
+ "--platform=manylinux_2_34_x86_64",
291
296
  "--platform=linux_x86_64",
292
297
  ]
293
298
  )
@@ -1017,6 +1017,8 @@ def __determine_entrypoint(manifest: Manifest) -> str:
1017
1017
  return "./main.py"
1018
1018
  elif manifest.type == ManifestType.GO:
1019
1019
  return "./main"
1020
+ elif manifest.type == ManifestType.BINARY:
1021
+ return "./main"
1020
1022
  elif manifest.type == ManifestType.JAVA:
1021
1023
  return "./main.jar"
1022
1024
  else:
@@ -118,6 +118,8 @@ class ManifestType(str, Enum):
118
118
  """Go format"""
119
119
  JAVA = "java"
120
120
  """Java format"""
121
+ BINARY = "binary"
122
+ """Binary format"""
121
123
 
122
124
 
123
125
  class ManifestRuntime(str, Enum):
@@ -1081,7 +1081,7 @@ class RunQueuing(BaseModel):
1081
1081
  queued. If False, the run will be queued.
1082
1082
  """
1083
1083
 
1084
- def __post_init_post_parse__(self):
1084
+ def model_post_init(self, __context) -> None:
1085
1085
  """
1086
1086
  Validations done after parsing the model.
1087
1087
 
@@ -1121,6 +1121,8 @@ class RunConfiguration(BaseModel):
1121
1121
  ID of the secrets collection to use for the run. Defaults to None.
1122
1122
  queuing : RunQueuing, optional
1123
1123
  Queuing configuration for the run. Defaults to None.
1124
+ integration_id : str, optional
1125
+ ID of the integration to use for the run. Defaults to None.
1124
1126
 
1125
1127
  Examples
1126
1128
  --------
@@ -1150,6 +1152,27 @@ class RunConfiguration(BaseModel):
1150
1152
  """ID of the secrets collection to use for the run."""
1151
1153
  queuing: RunQueuing | None = None
1152
1154
  """Queuing configuration for the run."""
1155
+ integration_id: str | None = None
1156
+ """ID of the integration to use for the run."""
1157
+
1158
+ def model_post_init(self, __context) -> None:
1159
+ """
1160
+ Validations done after parsing the model.
1161
+
1162
+ Raises
1163
+ ------
1164
+ ValueError
1165
+ If execution_class is an empty string.
1166
+ """
1167
+
1168
+ if self.integration_id is None or self.integration_id == "":
1169
+ return
1170
+
1171
+ integration_val = "integration"
1172
+ if self.execution_class is not None and self.execution_class != "" and self.execution_class != integration_val:
1173
+ raise ValueError(f"When integration_id is set, execution_class must be `{integration_val}` or None.")
1174
+
1175
+ self.execution_class = integration_val
1153
1176
 
1154
1177
  def resolve(
1155
1178
  self,
@@ -1292,7 +1315,7 @@ class ExternalRunResult(BaseModel):
1292
1315
  or `MULTI_FILE` output formats.
1293
1316
  """
1294
1317
 
1295
- def __post_init_post_parse__(self):
1318
+ def model_post_init(self, __context) -> None:
1296
1319
  """
1297
1320
  Validations done after parsing the model.
1298
1321
 
@@ -0,0 +1,87 @@
1
+ import unittest
2
+
3
+ from nextmv.cloud.instance import InstanceConfiguration
4
+
5
+
6
+ class TestInstanceConfigurationValidation(unittest.TestCase):
7
+ """Test validation logic in InstanceConfiguration.model_post_init."""
8
+
9
+ def test_no_integration_id_no_validation(self):
10
+ """Test that validation is skipped when integration_id is None or empty."""
11
+ # With None integration_id
12
+ config = InstanceConfiguration(integration_id=None, execution_class="small")
13
+ self.assertEqual(config.execution_class, "small")
14
+
15
+ # With empty string integration_id
16
+ config = InstanceConfiguration(integration_id="", execution_class="large")
17
+ self.assertEqual(config.execution_class, "large")
18
+
19
+ # With no integration_id specified
20
+ config = InstanceConfiguration(execution_class="medium")
21
+ self.assertEqual(config.execution_class, "medium")
22
+
23
+ def test_integration_id_with_integration_execution_class(self):
24
+ """Test that integration_id with execution_class='integration' is valid."""
25
+ config = InstanceConfiguration(integration_id="int-12345", execution_class="integration")
26
+ self.assertEqual(config.integration_id, "int-12345")
27
+ self.assertEqual(config.execution_class, "integration")
28
+
29
+ def test_integration_id_with_none_execution_class(self):
30
+ """Test that integration_id with execution_class=None sets it to 'integration'."""
31
+ config = InstanceConfiguration(integration_id="int-12345", execution_class=None)
32
+ self.assertEqual(config.integration_id, "int-12345")
33
+ self.assertEqual(config.execution_class, "integration")
34
+
35
+ def test_integration_id_without_execution_class(self):
36
+ """Test that integration_id without execution_class sets it to 'integration'."""
37
+ config = InstanceConfiguration(integration_id="int-12345")
38
+ self.assertEqual(config.integration_id, "int-12345")
39
+ self.assertEqual(config.execution_class, "integration")
40
+
41
+ def test_integration_id_with_empty_execution_class(self):
42
+ """Test that integration_id with execution_class='' sets it to 'integration'."""
43
+ config = InstanceConfiguration(integration_id="int-12345", execution_class="")
44
+ self.assertEqual(config.integration_id, "int-12345")
45
+ self.assertEqual(config.execution_class, "integration")
46
+
47
+ def test_integration_id_with_invalid_execution_class_raises_error(self):
48
+ """Test that integration_id with non-integration execution_class raises ValueError."""
49
+ invalid_classes = ["small", "medium", "large", "custom", "standard"]
50
+
51
+ for execution_class in invalid_classes:
52
+ with self.subTest(execution_class=execution_class):
53
+ with self.assertRaises(ValueError) as context:
54
+ InstanceConfiguration(integration_id="int-12345", execution_class=execution_class)
55
+
56
+ error_msg = str(context.exception)
57
+ self.assertIn("When integration_id is set", error_msg)
58
+ self.assertIn("execution_class must be `integration` or None", error_msg)
59
+
60
+ def test_integration_id_error_message_format(self):
61
+ """Test that the error message contains the expected format."""
62
+ with self.assertRaises(ValueError) as context:
63
+ InstanceConfiguration(integration_id="int-12345", execution_class="custom")
64
+
65
+ error_msg = str(context.exception)
66
+ # When using model_post_init, Pydantic wraps the error message
67
+ self.assertIn("When integration_id is set, execution_class must be `integration` or None.", error_msg)
68
+
69
+ def test_integration_id_with_other_configuration_options(self):
70
+ """Test that integration_id works correctly with other configuration options."""
71
+ config = InstanceConfiguration(
72
+ integration_id="int-12345", options={"max_runtime": 30}, secrets_collection_id="sc_1234567890"
73
+ )
74
+ self.assertEqual(config.integration_id, "int-12345")
75
+ self.assertEqual(config.execution_class, "integration")
76
+ self.assertEqual(config.options, {"max_runtime": 30})
77
+ self.assertEqual(config.secrets_collection_id, "sc_1234567890")
78
+
79
+ def test_no_integration_id_with_other_options(self):
80
+ """Test configuration without integration_id but with other options."""
81
+ config = InstanceConfiguration(
82
+ execution_class="small", options={"max_runtime": 60}, secrets_collection_id="sc_9876543210"
83
+ )
84
+ self.assertEqual(config.execution_class, "small")
85
+ self.assertEqual(config.options, {"max_runtime": 60})
86
+ self.assertEqual(config.secrets_collection_id, "sc_9876543210")
87
+ self.assertIsNone(config.integration_id)
@@ -8,6 +8,7 @@ from nextmv.run import (
8
8
  FormatOutput,
9
9
  Metadata,
10
10
  Run,
11
+ RunConfiguration,
11
12
  RunInformation,
12
13
  RunTypeConfiguration,
13
14
  run_duration,
@@ -206,3 +207,67 @@ class TestRunInformationToRun(unittest.TestCase):
206
207
 
207
208
  run = run_info.to_run()
208
209
  self.assertEqual(run.status_v2, status_v2)
210
+
211
+
212
+ class TestRunConfigurationValidation(unittest.TestCase):
213
+ """Test validation logic in RunConfiguration.model_post_init."""
214
+
215
+ def test_no_integration_id_no_validation(self):
216
+ """Test that validation is skipped when integration_id is None or empty."""
217
+ # With None integration_id
218
+ config = RunConfiguration(integration_id=None, execution_class="small")
219
+ self.assertEqual(config.execution_class, "small")
220
+
221
+ # With empty string integration_id
222
+ config = RunConfiguration(integration_id="", execution_class="large")
223
+ self.assertEqual(config.execution_class, "large")
224
+
225
+ # With no integration_id specified
226
+ config = RunConfiguration(execution_class="medium")
227
+ self.assertEqual(config.execution_class, "medium")
228
+
229
+ def test_integration_id_with_integration_execution_class(self):
230
+ """Test that integration_id with execution_class='integration' is valid."""
231
+ config = RunConfiguration(integration_id="int-12345", execution_class="integration")
232
+ self.assertEqual(config.integration_id, "int-12345")
233
+ self.assertEqual(config.execution_class, "integration")
234
+
235
+ def test_integration_id_with_none_execution_class(self):
236
+ """Test that integration_id with execution_class=None sets it to 'integration'."""
237
+ config = RunConfiguration(integration_id="int-12345", execution_class=None)
238
+ self.assertEqual(config.integration_id, "int-12345")
239
+ self.assertEqual(config.execution_class, "integration")
240
+
241
+ def test_integration_id_without_execution_class(self):
242
+ """Test that integration_id without execution_class sets it to 'integration'."""
243
+ config = RunConfiguration(integration_id="int-12345")
244
+ self.assertEqual(config.integration_id, "int-12345")
245
+ self.assertEqual(config.execution_class, "integration")
246
+
247
+ def test_integration_id_with_empty_execution_class(self):
248
+ """Test that integration_id with execution_class='' sets it to 'integration'."""
249
+ config = RunConfiguration(integration_id="int-12345", execution_class="")
250
+ self.assertEqual(config.integration_id, "int-12345")
251
+ self.assertEqual(config.execution_class, "integration")
252
+
253
+ def test_integration_id_with_invalid_execution_class_raises_error(self):
254
+ """Test that integration_id with non-integration execution_class raises ValueError."""
255
+ invalid_classes = ["small", "medium", "large", "custom", "standard"]
256
+
257
+ for execution_class in invalid_classes:
258
+ with self.subTest(execution_class=execution_class):
259
+ with self.assertRaises(ValueError) as context:
260
+ RunConfiguration(integration_id="int-12345", execution_class=execution_class)
261
+
262
+ error_msg = str(context.exception)
263
+ self.assertIn("When integration_id is set", error_msg)
264
+ self.assertIn("execution_class must be `integration` or None", error_msg)
265
+
266
+ def test_integration_id_error_message_format(self):
267
+ """Test that the error message contains the expected format."""
268
+ with self.assertRaises(ValueError) as context:
269
+ RunConfiguration(integration_id="int-12345", execution_class="custom")
270
+
271
+ error_msg = str(context.exception)
272
+ # When using model_post_init, Pydantic wraps the error message
273
+ self.assertIn("When integration_id is set, execution_class must be `integration` or None.", error_msg)
@@ -1 +0,0 @@
1
- __version__ = "v0.36.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes